mindcache 2.2.0 → 2.4.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/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { useState, useRef, useEffect } from 'react';
2
3
 
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -10,21 +11,173 @@ var __export = (target, all) => {
10
11
  __defProp(target, name, { get: all[name], enumerable: true });
11
12
  };
12
13
 
14
+ // src/local/IndexedDBAdapter.ts
15
+ var IndexedDBAdapter_exports = {};
16
+ __export(IndexedDBAdapter_exports, {
17
+ IndexedDBAdapter: () => IndexedDBAdapter
18
+ });
19
+ var IndexedDBAdapter;
20
+ var init_IndexedDBAdapter = __esm({
21
+ "src/local/IndexedDBAdapter.ts"() {
22
+ IndexedDBAdapter = class {
23
+ constructor(config = {}) {
24
+ this.config = config;
25
+ this.dbName = config.dbName || "mindcache_db";
26
+ this.storeName = config.storeName || "mindcache_store";
27
+ this.key = config.key || "mindcache_data";
28
+ }
29
+ mindcache = null;
30
+ unsubscribe = null;
31
+ saveTimeout = null;
32
+ db = null;
33
+ dbName;
34
+ storeName;
35
+ key;
36
+ async attach(mc) {
37
+ if (this.mindcache) {
38
+ this.detach();
39
+ }
40
+ this.mindcache = mc;
41
+ await this.initDB();
42
+ await this.load();
43
+ const listener = () => {
44
+ if (this.mindcache && !this.mindcache.isRemoteUpdate()) {
45
+ this.scheduleSave();
46
+ }
47
+ };
48
+ mc.subscribeToAll(listener);
49
+ this.unsubscribe = () => mc.unsubscribeFromAll(listener);
50
+ console.log("\u{1F5C4}\uFE0F IndexedDBAdapter: Attached to MindCache instance");
51
+ }
52
+ detach() {
53
+ if (this.unsubscribe) {
54
+ this.unsubscribe();
55
+ this.unsubscribe = null;
56
+ }
57
+ if (this.saveTimeout) {
58
+ clearTimeout(this.saveTimeout);
59
+ this.saveTimeout = null;
60
+ }
61
+ this.mindcache = null;
62
+ if (this.db) {
63
+ this.db.close();
64
+ this.db = null;
65
+ }
66
+ }
67
+ initDB() {
68
+ return new Promise((resolve, reject) => {
69
+ const request = indexedDB.open(this.dbName);
70
+ request.onerror = () => {
71
+ console.error("MindCache: IndexedDB error:", request.error);
72
+ reject(request.error);
73
+ };
74
+ request.onsuccess = () => {
75
+ const db = request.result;
76
+ if (!db.objectStoreNames.contains(this.storeName)) {
77
+ const currentVersion = db.version;
78
+ db.close();
79
+ const upgradeRequest = indexedDB.open(this.dbName, currentVersion + 1);
80
+ upgradeRequest.onerror = () => {
81
+ console.error("MindCache: IndexedDB upgrade error:", upgradeRequest.error);
82
+ reject(upgradeRequest.error);
83
+ };
84
+ upgradeRequest.onupgradeneeded = () => {
85
+ const upgradeDb = upgradeRequest.result;
86
+ if (!upgradeDb.objectStoreNames.contains(this.storeName)) {
87
+ upgradeDb.createObjectStore(this.storeName);
88
+ }
89
+ };
90
+ upgradeRequest.onsuccess = () => {
91
+ this.db = upgradeRequest.result;
92
+ resolve();
93
+ };
94
+ } else {
95
+ this.db = db;
96
+ resolve();
97
+ }
98
+ };
99
+ request.onupgradeneeded = () => {
100
+ const db = request.result;
101
+ if (!db.objectStoreNames.contains(this.storeName)) {
102
+ db.createObjectStore(this.storeName);
103
+ }
104
+ };
105
+ });
106
+ }
107
+ load() {
108
+ if (!this.db || !this.mindcache) {
109
+ return Promise.resolve();
110
+ }
111
+ return new Promise((resolve) => {
112
+ try {
113
+ const transaction = this.db.transaction([this.storeName], "readonly");
114
+ const store = transaction.objectStore(this.storeName);
115
+ const request = store.get(this.key);
116
+ request.onsuccess = () => {
117
+ if (request.result) {
118
+ this.mindcache.deserialize(request.result);
119
+ console.log("\u{1F5C4}\uFE0F IndexedDBAdapter: Loaded data from IndexedDB");
120
+ }
121
+ resolve();
122
+ };
123
+ request.onerror = () => {
124
+ console.error("MindCache: Failed to load from IndexedDB:", request.error);
125
+ resolve();
126
+ };
127
+ } catch (error) {
128
+ console.error("MindCache: Error accessing IndexedDB for load:", error);
129
+ resolve();
130
+ }
131
+ });
132
+ }
133
+ scheduleSave() {
134
+ if (this.saveTimeout) {
135
+ clearTimeout(this.saveTimeout);
136
+ }
137
+ this.saveTimeout = setTimeout(() => {
138
+ this.save();
139
+ this.saveTimeout = null;
140
+ }, this.config.debounceMs ?? 1e3);
141
+ }
142
+ save() {
143
+ if (!this.db || !this.mindcache) {
144
+ return;
145
+ }
146
+ try {
147
+ const data = this.mindcache.serialize();
148
+ const transaction = this.db.transaction([this.storeName], "readwrite");
149
+ const store = transaction.objectStore(this.storeName);
150
+ const request = store.put(data, this.key);
151
+ request.onsuccess = () => {
152
+ console.log("\u{1F5C4}\uFE0F IndexedDBAdapter: Saved to IndexedDB");
153
+ };
154
+ request.onerror = () => {
155
+ console.error("MindCache: Failed to save to IndexedDB:", request.error);
156
+ };
157
+ } catch (error) {
158
+ console.error("MindCache: Error accessing IndexedDB for save:", error);
159
+ }
160
+ }
161
+ };
162
+ }
163
+ });
164
+
13
165
  // src/cloud/CloudAdapter.ts
14
166
  var CloudAdapter_exports = {};
15
167
  __export(CloudAdapter_exports, {
16
168
  CloudAdapter: () => CloudAdapter
17
169
  });
18
- var DEFAULT_BASE_URL, RECONNECT_DELAY, MAX_RECONNECT_DELAY, CloudAdapter;
170
+ var RECONNECT_DELAY, MAX_RECONNECT_DELAY, CloudAdapter;
19
171
  var init_CloudAdapter = __esm({
20
172
  "src/cloud/CloudAdapter.ts"() {
21
- DEFAULT_BASE_URL = "wss://api.mindcache.io";
22
173
  RECONNECT_DELAY = 1e3;
23
174
  MAX_RECONNECT_DELAY = 3e4;
24
175
  CloudAdapter = class {
25
176
  constructor(config) {
26
177
  this.config = config;
27
- this.config.baseUrl = config.baseUrl || DEFAULT_BASE_URL;
178
+ if (!config.baseUrl) {
179
+ throw new Error("MindCache Cloud: baseUrl is required. Please provide the cloud API URL in your configuration.");
180
+ }
28
181
  }
29
182
  ws = null;
30
183
  queue = [];
@@ -85,6 +238,40 @@ var init_CloudAdapter = __esm({
85
238
  }
86
239
  this.mindcache = null;
87
240
  }
241
+ /**
242
+ * Fetch a short-lived WebSocket token from the API using the API key.
243
+ * This keeps the API key secure by only using it for a single HTTPS request,
244
+ * then using the short-lived token for the WebSocket connection.
245
+ *
246
+ * Supports two key formats:
247
+ * - API keys: mc_live_xxx or mc_test_xxx → Bearer token
248
+ * - Delegate keys: del_xxx:sec_xxx → ApiKey format
249
+ */
250
+ async fetchTokenWithApiKey() {
251
+ if (!this.config.apiKey) {
252
+ throw new Error("API key is required to fetch token");
253
+ }
254
+ const httpBaseUrl = this.config.baseUrl.replace("wss://", "https://").replace("ws://", "http://");
255
+ const isDelegate = this.config.apiKey.startsWith("del_") && this.config.apiKey.includes(":");
256
+ const authHeader = isDelegate ? `ApiKey ${this.config.apiKey}` : `Bearer ${this.config.apiKey}`;
257
+ const response = await fetch(`${httpBaseUrl}/api/ws-token`, {
258
+ method: "POST",
259
+ headers: {
260
+ "Content-Type": "application/json",
261
+ "Authorization": authHeader
262
+ },
263
+ body: JSON.stringify({
264
+ instanceId: this.config.instanceId,
265
+ permission: "write"
266
+ })
267
+ });
268
+ if (!response.ok) {
269
+ const error = await response.json().catch(() => ({ error: "Failed to get token" }));
270
+ throw new Error(error.error || `Failed to get WebSocket token: ${response.status}`);
271
+ }
272
+ const data = await response.json();
273
+ return data.token;
274
+ }
88
275
  /**
89
276
  * Connect to the cloud service
90
277
  */
@@ -94,13 +281,19 @@ var init_CloudAdapter = __esm({
94
281
  }
95
282
  this._state = "connecting";
96
283
  try {
97
- if (this.config.tokenProvider && !this.token) {
98
- this.token = await this.config.tokenProvider();
284
+ if (!this.token) {
285
+ if (this.config.tokenProvider) {
286
+ this.token = await this.config.tokenProvider();
287
+ } else if (this.config.apiKey) {
288
+ this.token = await this.fetchTokenWithApiKey();
289
+ }
99
290
  }
100
291
  let url = `${this.config.baseUrl}/sync/${this.config.instanceId}`;
101
292
  if (this.token) {
102
293
  url += `?token=${encodeURIComponent(this.token)}`;
103
294
  this.token = null;
295
+ } else {
296
+ throw new Error("MindCache Cloud: No authentication method available. Provide apiKey or tokenProvider.");
104
297
  }
105
298
  this.ws = new WebSocket(url);
106
299
  this.setupWebSocket();
@@ -162,12 +355,6 @@ var init_CloudAdapter = __esm({
162
355
  return;
163
356
  }
164
357
  this.ws.onopen = () => {
165
- if (this.config.apiKey) {
166
- this.ws.send(JSON.stringify({
167
- type: "auth",
168
- apiKey: this.config.apiKey
169
- }));
170
- }
171
358
  };
172
359
  this.ws.onmessage = (event) => {
173
360
  try {
@@ -175,6 +362,7 @@ var init_CloudAdapter = __esm({
175
362
  this.handleMessage(msg);
176
363
  } catch (error) {
177
364
  console.error("MindCache Cloud: Failed to parse message:", error);
365
+ console.error("Raw message:", typeof event.data === "string" ? event.data.slice(0, 200) : event.data);
178
366
  }
179
367
  };
180
368
  this.ws.onclose = () => {
@@ -182,10 +370,12 @@ var init_CloudAdapter = __esm({
182
370
  this.emit("disconnected");
183
371
  this.scheduleReconnect();
184
372
  };
185
- this.ws.onerror = (error) => {
373
+ this.ws.onerror = () => {
186
374
  this._state = "error";
187
- this.emit("error", new Error("WebSocket error"));
188
- console.error("MindCache Cloud: WebSocket error:", error);
375
+ const url = `${this.config.baseUrl}/sync/${this.config.instanceId}`;
376
+ console.error(`MindCache Cloud: WebSocket error connecting to ${url}`);
377
+ console.error("Check that the instance ID and API key are correct, and that the server is reachable.");
378
+ this.emit("error", new Error(`WebSocket connection failed to ${url}`));
189
379
  };
190
380
  }
191
381
  handleMessage(msg) {
@@ -262,15 +452,6 @@ var init_CloudAdapter = __esm({
262
452
  this.reconnectTimeout = setTimeout(async () => {
263
453
  this.reconnectTimeout = null;
264
454
  this.reconnectAttempts++;
265
- if (this.config.tokenProvider) {
266
- try {
267
- this.token = await this.config.tokenProvider();
268
- } catch (error) {
269
- console.error("MindCache Cloud: Failed to get token for reconnect:", error);
270
- this.emit("error", error);
271
- return;
272
- }
273
- }
274
455
  this.connect();
275
456
  }, delay);
276
457
  }
@@ -299,8 +480,8 @@ var init_CloudAdapter = __esm({
299
480
  var DEFAULT_KEY_ATTRIBUTES = {
300
481
  type: "text",
301
482
  contentTags: [],
302
- systemTags: ["prompt"],
303
- // visible by default
483
+ systemTags: ["SystemPrompt", "LLMWrite"],
484
+ // visible in system prompt and writable by LLM by default
304
485
  zIndex: 0,
305
486
  // Legacy - derived from systemTags
306
487
  readonly: false,
@@ -317,6 +498,65 @@ var MindCache = class {
317
498
  globalListeners = [];
318
499
  // Internal flag to prevent sync loops when receiving remote updates
319
500
  _isRemoteUpdate = false;
501
+ /**
502
+ * Normalize system tags: migrate old tags to new ones
503
+ * - 'prompt' → 'SystemPrompt'
504
+ * - 'readonly' → remove 'LLMWrite' (or add if not readonly)
505
+ */
506
+ normalizeSystemTags(tags) {
507
+ const normalized = [];
508
+ let hasSystemPrompt = false;
509
+ let hasLLMRead = false;
510
+ let hasLLMWrite = false;
511
+ let hasReadonly = false;
512
+ for (const tag of tags) {
513
+ if (tag === "SystemPrompt" || tag === "prompt") {
514
+ hasSystemPrompt = true;
515
+ } else if (tag === "LLMRead") {
516
+ hasLLMRead = true;
517
+ } else if (tag === "LLMWrite") {
518
+ hasLLMWrite = true;
519
+ } else if (tag === "readonly") {
520
+ hasReadonly = true;
521
+ } else if (tag === "protected") {
522
+ normalized.push(tag);
523
+ } else if (tag === "ApplyTemplate" || tag === "template") {
524
+ normalized.push("ApplyTemplate");
525
+ }
526
+ }
527
+ if (hasSystemPrompt) {
528
+ normalized.push("SystemPrompt");
529
+ }
530
+ if (hasLLMRead) {
531
+ normalized.push("LLMRead");
532
+ }
533
+ if (hasReadonly) {
534
+ normalized.push("readonly");
535
+ } else if (hasLLMWrite) {
536
+ normalized.push("LLMWrite");
537
+ } else {
538
+ normalized.push("LLMWrite");
539
+ }
540
+ return normalized;
541
+ }
542
+ /**
543
+ * Check if key should be visible in system prompt
544
+ */
545
+ hasSystemPrompt(tags) {
546
+ return tags.includes("SystemPrompt") || tags.includes("prompt");
547
+ }
548
+ /**
549
+ * Check if key can be read by LLM (has LLMRead or SystemPrompt)
550
+ */
551
+ hasLLMRead(tags) {
552
+ return tags.includes("LLMRead") || tags.includes("SystemPrompt") || tags.includes("prompt");
553
+ }
554
+ /**
555
+ * Check if key can be written by LLM (has LLMWrite and not readonly)
556
+ */
557
+ hasLLMWrite(tags) {
558
+ return tags.includes("LLMWrite") && !tags.includes("readonly");
559
+ }
320
560
  // Cloud sync state
321
561
  _cloudAdapter = null;
322
562
  _connectionState = "disconnected";
@@ -325,15 +565,33 @@ var MindCache = class {
325
565
  _cloudConfig = null;
326
566
  // Access level for system operations
327
567
  _accessLevel = "user";
568
+ _initPromise = null;
328
569
  constructor(options) {
329
570
  if (options?.accessLevel) {
330
571
  this._accessLevel = options.accessLevel;
331
572
  }
573
+ if (options?.cloud && options?.indexedDB) {
574
+ throw new Error(
575
+ "MindCache: Cannot use both cloud and indexedDB together. Choose one persistence method to avoid data conflicts. Use cloud for real-time sync, or indexedDB for local-only persistence."
576
+ );
577
+ }
578
+ const initPromises = [];
332
579
  if (options?.cloud) {
333
580
  this._cloudConfig = options.cloud;
334
581
  this._isLoaded = false;
335
582
  this._connectionState = "disconnected";
336
- this._initCloud();
583
+ initPromises.push(this._initCloud());
584
+ }
585
+ if (options?.indexedDB) {
586
+ this._isLoaded = false;
587
+ initPromises.push(this._initIndexedDB(options.indexedDB));
588
+ }
589
+ if (initPromises.length > 0) {
590
+ this._initPromise = Promise.all(initPromises).then(() => {
591
+ if (!this._cloudConfig) {
592
+ this._isLoaded = true;
593
+ }
594
+ });
337
595
  }
338
596
  }
339
597
  /**
@@ -353,9 +611,11 @@ var MindCache = class {
353
611
  return;
354
612
  }
355
613
  try {
356
- const { CloudAdapter: CloudAdapter2 } = await Promise.resolve().then(() => (init_CloudAdapter(), CloudAdapter_exports));
357
- const configUrl = this._cloudConfig.baseUrl || "https://api.mindcache.io";
358
- const baseUrl = configUrl.replace("https://", "wss://").replace("http://", "ws://");
614
+ const CloudAdapter2 = await this._getCloudAdapterClass();
615
+ if (!this._cloudConfig.baseUrl) {
616
+ throw new Error("MindCache Cloud: baseUrl is required. Please provide the cloud API URL in your configuration.");
617
+ }
618
+ const baseUrl = this._cloudConfig.baseUrl.replace("https://", "wss://").replace("http://", "ws://");
359
619
  const adapter = new CloudAdapter2({
360
620
  instanceId: this._cloudConfig.instanceId,
361
621
  projectId: this._cloudConfig.projectId || "default",
@@ -411,6 +671,19 @@ var MindCache = class {
411
671
  this._isLoaded = true;
412
672
  }
413
673
  }
674
+ async _initIndexedDB(config) {
675
+ try {
676
+ const IndexedDBAdapter2 = await this._getIndexedDBAdapterClass();
677
+ const adapter = new IndexedDBAdapter2(config);
678
+ await adapter.attach(this);
679
+ } catch (error) {
680
+ console.error("MindCache: Failed to initialize IndexedDB:", error);
681
+ }
682
+ }
683
+ async _getIndexedDBAdapterClass() {
684
+ const { IndexedDBAdapter: IndexedDBAdapter2 } = await Promise.resolve().then(() => (init_IndexedDBAdapter(), IndexedDBAdapter_exports));
685
+ return IndexedDBAdapter2;
686
+ }
414
687
  /**
415
688
  * Get the current cloud connection state
416
689
  */
@@ -423,12 +696,46 @@ var MindCache = class {
423
696
  get isLoaded() {
424
697
  return this._isLoaded;
425
698
  }
699
+ /**
700
+ * Protected method to load CloudAdapter class.
701
+ * Can be overridden/mocked for testing.
702
+ */
703
+ async _getCloudAdapterClass() {
704
+ const { CloudAdapter: CloudAdapter2 } = await Promise.resolve().then(() => (init_CloudAdapter(), CloudAdapter_exports));
705
+ return CloudAdapter2;
706
+ }
426
707
  /**
427
708
  * Check if this instance is connected to cloud
428
709
  */
429
710
  get isCloud() {
430
711
  return this._cloudConfig !== null;
431
712
  }
713
+ /**
714
+ * Wait for initial sync to complete (or resolve immediately if already synced/local).
715
+ * Useful for scripts or linear execution flows.
716
+ */
717
+ async waitForSync() {
718
+ if (this._isLoaded) {
719
+ return;
720
+ }
721
+ if (this._initPromise) {
722
+ await this._initPromise;
723
+ }
724
+ if (this._isLoaded) {
725
+ return;
726
+ }
727
+ return new Promise((resolve) => {
728
+ if (!this._cloudAdapter) {
729
+ resolve();
730
+ return;
731
+ }
732
+ const handler = () => {
733
+ this._cloudAdapter?.off("synced", handler);
734
+ resolve();
735
+ };
736
+ this._cloudAdapter.on("synced", handler);
737
+ });
738
+ }
432
739
  /**
433
740
  * Disconnect from cloud (if connected)
434
741
  */
@@ -495,7 +802,7 @@ var MindCache = class {
495
802
  if (!entry) {
496
803
  return void 0;
497
804
  }
498
- if (entry.attributes.template) {
805
+ if (entry.attributes.systemTags?.includes("ApplyTemplate") || entry.attributes.systemTags?.includes("template") || entry.attributes.template) {
499
806
  const processingStack = _processingStack || /* @__PURE__ */ new Set();
500
807
  if (processingStack.has(key)) {
501
808
  return entry.value;
@@ -544,77 +851,87 @@ var MindCache = class {
544
851
  ...DEFAULT_KEY_ATTRIBUTES,
545
852
  contentTags: [],
546
853
  // Fresh array
547
- systemTags: ["prompt"],
854
+ systemTags: ["SystemPrompt", "LLMWrite"],
548
855
  // Fresh array with default
549
856
  tags: [],
550
857
  // Fresh array
551
858
  zIndex: 0
552
859
  };
553
860
  const finalAttributes = attributes ? { ...baseAttributes, ...attributes } : baseAttributes;
861
+ let systemTags = this.normalizeSystemTags(finalAttributes.systemTags || []);
554
862
  if (attributes) {
555
- let systemTags2 = [...finalAttributes.systemTags || []];
556
863
  if ("readonly" in attributes) {
557
- if (attributes.readonly && !systemTags2.includes("readonly")) {
558
- systemTags2.push("readonly");
559
- } else if (!attributes.readonly && !wasHardcoded) {
560
- systemTags2 = systemTags2.filter((t) => t !== "readonly");
864
+ if (attributes.readonly) {
865
+ systemTags = systemTags.filter((t) => t !== "LLMWrite");
866
+ if (!systemTags.includes("readonly")) {
867
+ systemTags.push("readonly");
868
+ }
869
+ } else if (!wasHardcoded) {
870
+ if (!systemTags.includes("LLMWrite")) {
871
+ systemTags.push("LLMWrite");
872
+ }
873
+ systemTags = systemTags.filter((t) => t !== "readonly");
561
874
  }
562
875
  }
563
876
  if ("visible" in attributes) {
564
- if (attributes.visible && !systemTags2.includes("prompt")) {
565
- systemTags2.push("prompt");
566
- } else if (!attributes.visible) {
567
- systemTags2 = systemTags2.filter((t) => t !== "prompt");
877
+ if (attributes.visible) {
878
+ if (!systemTags.includes("SystemPrompt")) {
879
+ systemTags.push("SystemPrompt");
880
+ }
881
+ systemTags = systemTags.filter((t) => t !== "prompt");
882
+ } else {
883
+ systemTags = systemTags.filter((t) => t !== "SystemPrompt" && t !== "prompt");
568
884
  }
569
885
  }
886
+ if ("systemTags" in attributes && Array.isArray(attributes.systemTags)) {
887
+ systemTags = this.normalizeSystemTags(attributes.systemTags);
888
+ }
570
889
  if ("hardcoded" in attributes) {
571
- if (attributes.hardcoded && !systemTags2.includes("protected")) {
572
- systemTags2.push("protected");
890
+ if (attributes.hardcoded && !systemTags.includes("protected")) {
891
+ systemTags.push("protected");
573
892
  } else if (!attributes.hardcoded && !wasHardcoded) {
574
- systemTags2 = systemTags2.filter((t) => t !== "protected");
893
+ systemTags = systemTags.filter((t) => t !== "protected");
575
894
  }
576
- if (wasHardcoded && !systemTags2.includes("protected")) {
577
- systemTags2.push("protected");
895
+ if (wasHardcoded && !systemTags.includes("protected")) {
896
+ systemTags.push("protected");
578
897
  }
579
898
  } else if (wasHardcoded) {
580
- if (!systemTags2.includes("protected")) {
581
- systemTags2.push("protected");
899
+ if (!systemTags.includes("protected")) {
900
+ systemTags.push("protected");
582
901
  }
583
902
  }
584
903
  if ("template" in attributes) {
585
- if (attributes.template && !wasHardcoded && !systemTags2.includes("template")) {
586
- systemTags2.push("template");
904
+ if (attributes.template && !wasHardcoded && !systemTags.includes("ApplyTemplate") && !systemTags.includes("template")) {
905
+ systemTags.push("ApplyTemplate");
587
906
  } else if (!attributes.template || wasHardcoded) {
588
- systemTags2 = systemTags2.filter((t) => t !== "template");
907
+ systemTags = systemTags.filter((t) => t !== "ApplyTemplate" && t !== "template");
589
908
  }
590
909
  }
591
- finalAttributes.systemTags = systemTags2;
592
910
  } else if (wasHardcoded) {
593
- let systemTags2 = [...finalAttributes.systemTags || []];
594
- if (!systemTags2.includes("protected")) {
595
- systemTags2.push("protected");
911
+ if (!systemTags.includes("protected")) {
912
+ systemTags.push("protected");
596
913
  }
597
- if (!systemTags2.includes("readonly")) {
598
- systemTags2.push("readonly");
914
+ systemTags = systemTags.filter((t) => t !== "LLMWrite");
915
+ if (!systemTags.includes("readonly")) {
916
+ systemTags.push("readonly");
599
917
  }
600
- systemTags2 = systemTags2.filter((t) => t !== "template");
601
- finalAttributes.systemTags = systemTags2;
918
+ systemTags = systemTags.filter((t) => t !== "template");
602
919
  }
603
- let systemTags = finalAttributes.systemTags || [];
604
920
  if (wasHardcoded && !systemTags.includes("protected")) {
605
- systemTags = [...systemTags, "protected"];
921
+ systemTags.push("protected");
606
922
  }
607
923
  if (systemTags.includes("protected")) {
924
+ systemTags = systemTags.filter((t) => t !== "LLMWrite");
608
925
  if (!systemTags.includes("readonly")) {
609
- systemTags = [...systemTags, "readonly"];
926
+ systemTags.push("readonly");
610
927
  }
611
928
  systemTags = systemTags.filter((t) => t !== "template");
612
- finalAttributes.systemTags = systemTags;
613
929
  }
614
- finalAttributes.readonly = systemTags.includes("readonly");
615
- finalAttributes.visible = systemTags.includes("prompt");
930
+ finalAttributes.systemTags = systemTags;
931
+ finalAttributes.readonly = systemTags.includes("readonly") || !systemTags.includes("LLMWrite");
932
+ finalAttributes.visible = this.hasSystemPrompt(systemTags);
616
933
  finalAttributes.hardcoded = wasHardcoded || systemTags.includes("protected");
617
- finalAttributes.template = systemTags.includes("template");
934
+ finalAttributes.template = systemTags.includes("ApplyTemplate") || systemTags.includes("template");
618
935
  if (attributes && "tags" in attributes && attributes.tags) {
619
936
  finalAttributes.contentTags = [...attributes.tags];
620
937
  }
@@ -635,21 +952,25 @@ var MindCache = class {
635
952
  return;
636
953
  }
637
954
  this._isRemoteUpdate = true;
638
- const systemTags = attributes.systemTags || [];
639
- if (!attributes.systemTags) {
955
+ let systemTags = attributes.systemTags || [];
956
+ if (!attributes.systemTags || systemTags.length === 0) {
957
+ systemTags = [];
640
958
  if (attributes.visible !== false) {
641
959
  systemTags.push("prompt");
642
960
  }
643
961
  if (attributes.readonly) {
644
962
  systemTags.push("readonly");
963
+ } else {
964
+ systemTags.push("LLMWrite");
645
965
  }
646
966
  if (attributes.hardcoded) {
647
967
  systemTags.push("protected");
648
968
  }
649
969
  if (attributes.template) {
650
- systemTags.push("template");
970
+ systemTags.push("ApplyTemplate");
651
971
  }
652
972
  }
973
+ systemTags = this.normalizeSystemTags(systemTags);
653
974
  const contentTags = attributes.contentTags || attributes.tags || [];
654
975
  this.stm[key] = {
655
976
  value,
@@ -659,10 +980,11 @@ var MindCache = class {
659
980
  systemTags,
660
981
  zIndex: attributes.zIndex ?? 0,
661
982
  tags: contentTags,
662
- readonly: systemTags.includes("readonly"),
663
- visible: systemTags.includes("prompt"),
983
+ // Sync legacy attributes FROM normalized systemTags
984
+ readonly: systemTags.includes("readonly") || !systemTags.includes("LLMWrite"),
985
+ visible: this.hasSystemPrompt(systemTags),
664
986
  hardcoded: systemTags.includes("protected"),
665
- template: systemTags.includes("template")
987
+ template: systemTags.includes("ApplyTemplate") || systemTags.includes("template")
666
988
  }
667
989
  };
668
990
  if (this.listeners[key]) {
@@ -717,39 +1039,55 @@ var MindCache = class {
717
1039
  }
718
1040
  }
719
1041
  entry.attributes = { ...entry.attributes, ...allowedAttributes };
720
- if ("readonly" in attributes || "visible" in attributes || "template" in attributes) {
721
- let newSystemTags = [];
722
- if (entry.attributes.readonly) {
723
- newSystemTags.push("readonly");
724
- }
725
- if (entry.attributes.visible) {
726
- newSystemTags.push("prompt");
727
- }
728
- if (entry.attributes.template) {
729
- newSystemTags.push("template");
730
- }
731
- if (wasHardcoded || entry.attributes.hardcoded) {
732
- newSystemTags.push("protected");
1042
+ if ("readonly" in attributes || "visible" in attributes || "template" in attributes || "systemTags" in attributes) {
1043
+ let newSystemTags = entry.attributes.systemTags || [];
1044
+ if ("systemTags" in attributes && Array.isArray(attributes.systemTags)) {
1045
+ newSystemTags = this.normalizeSystemTags(attributes.systemTags);
1046
+ } else {
1047
+ newSystemTags = [];
1048
+ if (!entry.attributes.readonly) {
1049
+ newSystemTags.push("LLMWrite");
1050
+ } else {
1051
+ newSystemTags.push("readonly");
1052
+ }
1053
+ if (entry.attributes.visible) {
1054
+ newSystemTags.push("SystemPrompt");
1055
+ }
1056
+ if (entry.attributes.template) {
1057
+ newSystemTags.push("ApplyTemplate");
1058
+ }
1059
+ if (wasHardcoded || entry.attributes.hardcoded) {
1060
+ newSystemTags.push("protected");
1061
+ }
1062
+ newSystemTags = this.normalizeSystemTags(newSystemTags);
733
1063
  }
734
1064
  if (newSystemTags.includes("protected")) {
1065
+ newSystemTags = newSystemTags.filter((t) => t !== "LLMWrite");
735
1066
  if (!newSystemTags.includes("readonly")) {
736
1067
  newSystemTags.push("readonly");
737
1068
  }
738
- newSystemTags = newSystemTags.filter((t) => t !== "template");
1069
+ newSystemTags = newSystemTags.filter((t) => t !== "ApplyTemplate" && t !== "template");
739
1070
  entry.attributes.readonly = true;
740
1071
  entry.attributes.template = false;
741
1072
  }
742
1073
  entry.attributes.systemTags = newSystemTags;
1074
+ entry.attributes.readonly = newSystemTags.includes("readonly") || !newSystemTags.includes("LLMWrite");
1075
+ entry.attributes.visible = this.hasSystemPrompt(newSystemTags);
1076
+ entry.attributes.template = newSystemTags.includes("ApplyTemplate") || newSystemTags.includes("template");
743
1077
  } else if (wasHardcoded) {
744
- let systemTags = [...entry.attributes.systemTags || []];
1078
+ let systemTags = this.normalizeSystemTags(entry.attributes.systemTags || []);
745
1079
  if (!systemTags.includes("protected")) {
746
1080
  systemTags.push("protected");
747
1081
  }
1082
+ systemTags = systemTags.filter((t) => t !== "LLMWrite");
748
1083
  if (!systemTags.includes("readonly")) {
749
1084
  systemTags.push("readonly");
750
1085
  }
751
- systemTags = systemTags.filter((t) => t !== "template");
1086
+ systemTags = systemTags.filter((t) => t !== "ApplyTemplate" && t !== "template");
752
1087
  entry.attributes.systemTags = systemTags;
1088
+ entry.attributes.readonly = true;
1089
+ entry.attributes.visible = this.hasSystemPrompt(systemTags);
1090
+ entry.attributes.template = false;
753
1091
  }
754
1092
  if (wasHardcoded) {
755
1093
  entry.attributes.hardcoded = true;
@@ -991,8 +1329,9 @@ var MindCache = class {
991
1329
  const sortedKeys = this.getSortedKeys();
992
1330
  sortedKeys.forEach((key) => {
993
1331
  const entry = this.stm[key];
994
- if (entry.attributes.visible) {
995
- const processedValue = entry.attributes.template ? this.get_value(key) : entry.value;
1332
+ if (this.hasLLMRead(entry.attributes.systemTags) || entry.attributes.visible) {
1333
+ const hasTemplate = entry.attributes.systemTags?.includes("ApplyTemplate") || entry.attributes.systemTags?.includes("template") || entry.attributes.template;
1334
+ const processedValue = hasTemplate ? this.get_value(key) : entry.value;
996
1335
  apiData.push({
997
1336
  key,
998
1337
  value: processedValue,
@@ -1018,7 +1357,7 @@ var MindCache = class {
1018
1357
  const sortedKeys = this.getSortedKeys();
1019
1358
  sortedKeys.forEach((key) => {
1020
1359
  const entry = this.stm[key];
1021
- if (entry.attributes.visible && entry.attributes.type === "image" && entry.attributes.contentType) {
1360
+ if ((this.hasLLMRead(entry.attributes.systemTags) || entry.attributes.visible) && entry.attributes.type === "image" && entry.attributes.contentType) {
1022
1361
  const dataUrl = this.createDataUrl(entry.value, entry.attributes.contentType);
1023
1362
  imageParts.push({
1024
1363
  type: "file",
@@ -1057,6 +1396,7 @@ var MindCache = class {
1057
1396
  }
1058
1397
  deserialize(data) {
1059
1398
  if (typeof data === "object" && data !== null) {
1399
+ this._isRemoteUpdate = true;
1060
1400
  this.clear();
1061
1401
  Object.entries(data).forEach(([key, entry]) => {
1062
1402
  if (entry && typeof entry === "object" && "value" in entry && "attributes" in entry) {
@@ -1065,21 +1405,24 @@ var MindCache = class {
1065
1405
  return;
1066
1406
  }
1067
1407
  let systemTags = attrs.systemTags || [];
1068
- if (!attrs.systemTags) {
1408
+ if (!attrs.systemTags || systemTags.length === 0) {
1069
1409
  systemTags = [];
1070
1410
  if (attrs.visible !== false) {
1071
1411
  systemTags.push("prompt");
1072
1412
  }
1073
1413
  if (attrs.readonly) {
1074
1414
  systemTags.push("readonly");
1415
+ } else {
1416
+ systemTags.push("LLMWrite");
1075
1417
  }
1076
1418
  if (attrs.hardcoded) {
1077
1419
  systemTags.push("protected");
1078
1420
  }
1079
1421
  if (attrs.template) {
1080
- systemTags.push("template");
1422
+ systemTags.push("ApplyTemplate");
1081
1423
  }
1082
1424
  }
1425
+ systemTags = this.normalizeSystemTags(systemTags);
1083
1426
  const contentTags = attrs.contentTags || attrs.tags || [];
1084
1427
  this.stm[key] = {
1085
1428
  value: entry.value,
@@ -1088,17 +1431,18 @@ var MindCache = class {
1088
1431
  contentTags,
1089
1432
  systemTags,
1090
1433
  zIndex: attrs.zIndex ?? 0,
1091
- // Sync legacy attributes
1434
+ // Sync legacy attributes FROM normalized systemTags
1092
1435
  tags: contentTags,
1093
- readonly: systemTags.includes("readonly"),
1094
- visible: systemTags.includes("prompt"),
1436
+ readonly: systemTags.includes("readonly") || !systemTags.includes("LLMWrite"),
1437
+ visible: this.hasSystemPrompt(systemTags),
1095
1438
  hardcoded: systemTags.includes("protected"),
1096
- template: systemTags.includes("template")
1439
+ template: systemTags.includes("ApplyTemplate") || systemTags.includes("template")
1097
1440
  }
1098
1441
  };
1099
1442
  }
1100
1443
  });
1101
1444
  this.notifyGlobalListeners();
1445
+ this._isRemoteUpdate = false;
1102
1446
  }
1103
1447
  }
1104
1448
  get_system_prompt() {
@@ -1107,13 +1451,14 @@ var MindCache = class {
1107
1451
  const sortedKeys = this.getSortedKeys();
1108
1452
  sortedKeys.forEach((key) => {
1109
1453
  const entry = this.stm[key];
1110
- if (entry.attributes.visible) {
1454
+ if (this.hasLLMRead(entry.attributes.systemTags) || entry.attributes.visible) {
1111
1455
  if (entry.attributes.type === "image") {
1112
1456
  promptLines.push(`image ${key} available`);
1113
1457
  return;
1114
1458
  }
1115
1459
  if (entry.attributes.type === "file") {
1116
- if (entry.attributes.readonly) {
1460
+ const canWrite2 = this.hasLLMWrite(entry.attributes.systemTags) || !entry.attributes.readonly && !entry.attributes.systemTags.includes("readonly");
1461
+ if (!canWrite2) {
1117
1462
  promptLines.push(`${key}: [${entry.attributes.type.toUpperCase()}] - ${entry.attributes.contentType || "unknown format"}`);
1118
1463
  } else {
1119
1464
  const sanitizedKey = key.replace(/[^a-zA-Z0-9_-]/g, "_");
@@ -1123,7 +1468,8 @@ var MindCache = class {
1123
1468
  }
1124
1469
  const value = this.get_value(key);
1125
1470
  const formattedValue = typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
1126
- if (entry.attributes.readonly) {
1471
+ const canWrite = this.hasLLMWrite(entry.attributes.systemTags) || !entry.attributes.readonly && !entry.attributes.systemTags.includes("readonly");
1472
+ if (!canWrite) {
1127
1473
  promptLines.push(`${key}: ${formattedValue}`);
1128
1474
  } else {
1129
1475
  const sanitizedKey = key.replace(/[^a-zA-Z0-9_-]/g, "_");
@@ -1151,7 +1497,7 @@ var MindCache = class {
1151
1497
  const sortedKeys = this.getSortedKeys();
1152
1498
  const writableKeys = sortedKeys.filter((key) => {
1153
1499
  const entry = this.stm[key];
1154
- return !entry.attributes.readonly;
1500
+ return this.hasLLMWrite(entry.attributes.systemTags) || !entry.attributes.readonly && !entry.attributes.systemTags.includes("readonly");
1155
1501
  });
1156
1502
  writableKeys.forEach((key) => {
1157
1503
  const sanitizedKey = key.replace(/[^a-zA-Z0-9_-]/g, "_");
@@ -1226,7 +1572,8 @@ var MindCache = class {
1226
1572
  return null;
1227
1573
  }
1228
1574
  const entry = this.stm[originalKey];
1229
- if (entry && entry.attributes.readonly) {
1575
+ const canWrite = entry && (this.hasLLMWrite(entry.attributes.systemTags) || !entry.attributes.readonly && !entry.attributes.systemTags.includes("readonly"));
1576
+ if (!canWrite) {
1230
1577
  return null;
1231
1578
  }
1232
1579
  this.set_value(originalKey, value);
@@ -1473,7 +1820,7 @@ var MindCache = class {
1473
1820
  entry.attributes.readonly = tags.includes("readonly");
1474
1821
  entry.attributes.visible = tags.includes("prompt");
1475
1822
  entry.attributes.hardcoded = tags.includes("protected");
1476
- entry.attributes.template = tags.includes("template");
1823
+ entry.attributes.template = tags.includes("ApplyTemplate") || tags.includes("template");
1477
1824
  }
1478
1825
  toMarkdown() {
1479
1826
  const now = /* @__PURE__ */ new Date();
@@ -1714,6 +2061,8 @@ var MindCache = class {
1714
2061
  }
1715
2062
  if (attrs.readonly) {
1716
2063
  systemTags.push("readonly");
2064
+ } else {
2065
+ systemTags.push("LLMWrite");
1717
2066
  }
1718
2067
  if (attrs.hardcoded) {
1719
2068
  systemTags.push("protected");
@@ -1721,7 +2070,9 @@ var MindCache = class {
1721
2070
  if (attrs.template) {
1722
2071
  systemTags.push("template");
1723
2072
  }
1724
- attrs.systemTags = systemTags;
2073
+ attrs.systemTags = this.normalizeSystemTags(systemTags);
2074
+ } else {
2075
+ attrs.systemTags = this.normalizeSystemTags(attrs.systemTags);
1725
2076
  }
1726
2077
  if (!attrs.contentTags) {
1727
2078
  attrs.contentTags = [];
@@ -1729,6 +2080,11 @@ var MindCache = class {
1729
2080
  if (!attrs.tags) {
1730
2081
  attrs.tags = [...attrs.contentTags];
1731
2082
  }
2083
+ const normalizedTags = attrs.systemTags || [];
2084
+ attrs.readonly = normalizedTags.includes("readonly") || !normalizedTags.includes("LLMWrite");
2085
+ attrs.visible = this.hasSystemPrompt(normalizedTags);
2086
+ attrs.hardcoded = normalizedTags.includes("protected");
2087
+ attrs.template = normalizedTags.includes("ApplyTemplate") || normalizedTags.includes("template");
1732
2088
  this.stm[key] = {
1733
2089
  value: entry.value,
1734
2090
  attributes: attrs
@@ -1744,6 +2100,43 @@ var mindcache = new MindCache();
1744
2100
  init_CloudAdapter();
1745
2101
  init_CloudAdapter();
1746
2102
 
1747
- export { CloudAdapter, DEFAULT_KEY_ATTRIBUTES, MindCache, mindcache };
2103
+ // src/local/index.ts
2104
+ init_IndexedDBAdapter();
2105
+ function useMindCache(options) {
2106
+ const [isLoaded, setIsLoaded] = useState(false);
2107
+ const [error, setError] = useState(null);
2108
+ const mindcacheRef = useRef(null);
2109
+ const initializingRef = useRef(false);
2110
+ useEffect(() => {
2111
+ if (initializingRef.current) {
2112
+ return;
2113
+ }
2114
+ initializingRef.current = true;
2115
+ const initialize = async () => {
2116
+ try {
2117
+ const mc = new MindCache(options);
2118
+ mindcacheRef.current = mc;
2119
+ await mc.waitForSync();
2120
+ setIsLoaded(true);
2121
+ } catch (err) {
2122
+ setError(err instanceof Error ? err : new Error(String(err)));
2123
+ setIsLoaded(true);
2124
+ }
2125
+ };
2126
+ initialize();
2127
+ return () => {
2128
+ if (mindcacheRef.current) {
2129
+ mindcacheRef.current.disconnect();
2130
+ }
2131
+ };
2132
+ }, []);
2133
+ return {
2134
+ mindcache: mindcacheRef.current,
2135
+ isLoaded,
2136
+ error
2137
+ };
2138
+ }
2139
+
2140
+ export { CloudAdapter, DEFAULT_KEY_ATTRIBUTES, IndexedDBAdapter, MindCache, mindcache, useMindCache };
1748
2141
  //# sourceMappingURL=index.mjs.map
1749
2142
  //# sourceMappingURL=index.mjs.map