mindcache 3.4.0 → 3.4.2

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
@@ -46,7 +46,7 @@ var init_IndexedDBAdapter = __esm({
46
46
  await this.initDB();
47
47
  await this.load();
48
48
  const listener = () => {
49
- if (this.mindcache && !this.mindcache.isRemoteUpdate()) {
49
+ if (this.mindcache) {
50
50
  this.scheduleSave();
51
51
  }
52
52
  };
@@ -426,15 +426,21 @@ var init_CloudAdapter = __esm({
426
426
  var DEFAULT_KEY_ATTRIBUTES = {
427
427
  type: "text",
428
428
  contentTags: [],
429
- systemTags: ["SystemPrompt", "LLMWrite"],
430
- // visible in system prompt and writable by LLM by default
431
- zIndex: 0,
432
- // Legacy - derived from systemTags
433
- readonly: false,
434
- visible: true,
435
- hardcoded: false,
436
- template: false,
437
- tags: []
429
+ systemTags: [],
430
+ // Keys are private by default - explicitly add SystemPrompt/LLMRead/LLMWrite to enable LLM access
431
+ zIndex: 0
432
+ };
433
+ var SystemTagHelpers = {
434
+ /** Check if key is writable by LLM */
435
+ isLLMWritable: (attrs) => attrs.systemTags.includes("LLMWrite"),
436
+ /** Check if key is readable by LLM (in context or via tools) */
437
+ isLLMReadable: (attrs) => attrs.systemTags.includes("SystemPrompt") || attrs.systemTags.includes("LLMRead"),
438
+ /** Check if key is included in system prompt */
439
+ isInSystemPrompt: (attrs) => attrs.systemTags.includes("SystemPrompt"),
440
+ /** Check if key is protected from deletion */
441
+ isProtected: (attrs) => attrs.systemTags.includes("protected"),
442
+ /** Check if key uses template injection */
443
+ hasTemplateInjection: (attrs) => attrs.systemTags.includes("ApplyTemplate")
438
444
  };
439
445
 
440
446
  // src/core/MindCache.ts
@@ -450,38 +456,16 @@ var MindCache = class {
450
456
  version = "3.3.2";
451
457
  // Internal flag to prevent sync loops when receiving remote updates
452
458
  // (Less critical with Yjs but kept for API compat)
453
- _isRemoteUpdate = false;
454
459
  normalizeSystemTags(tags) {
455
460
  const normalized = [];
456
- let hasSystemPrompt = false;
457
- let hasLLMRead = false;
458
- let hasLLMWrite = false;
459
- let hasReadonly = false;
461
+ const seen = /* @__PURE__ */ new Set();
460
462
  for (const tag of tags) {
461
- if (tag === "SystemPrompt" || tag === "prompt") {
462
- hasSystemPrompt = true;
463
- } else if (tag === "LLMRead") {
464
- hasLLMRead = true;
465
- } else if (tag === "LLMWrite") {
466
- hasLLMWrite = true;
467
- } else if (tag === "readonly") {
468
- hasReadonly = true;
469
- } else if (tag === "protected") {
470
- normalized.push(tag);
471
- } else if (tag === "ApplyTemplate" || tag === "template") {
472
- normalized.push("ApplyTemplate");
473
- }
474
- }
475
- if (hasSystemPrompt) {
476
- normalized.push("SystemPrompt");
477
- }
478
- if (hasLLMRead) {
479
- normalized.push("LLMRead");
480
- }
481
- if (hasReadonly) {
482
- normalized.push("readonly");
483
- } else if (hasLLMWrite) {
484
- normalized.push("LLMWrite");
463
+ if (["SystemPrompt", "LLMRead", "LLMWrite", "protected", "ApplyTemplate"].includes(tag)) {
464
+ if (!seen.has(tag)) {
465
+ seen.add(tag);
466
+ normalized.push(tag);
467
+ }
468
+ }
485
469
  }
486
470
  return normalized;
487
471
  }
@@ -872,10 +856,6 @@ var MindCache = class {
872
856
  this._idbProvider = null;
873
857
  }
874
858
  }
875
- // Legacy bridge
876
- isRemoteUpdate() {
877
- return false;
878
- }
879
859
  // Serialize state
880
860
  serialize() {
881
861
  const json = {};
@@ -912,16 +892,10 @@ var MindCache = class {
912
892
  const attrs = entry.attributes || {};
913
893
  const normalizedAttrs = {
914
894
  type: attrs.type || "text",
895
+ contentType: attrs.contentType,
915
896
  contentTags: attrs.contentTags || [],
916
- systemTags: attrs.systemTags || this.normalizeSystemTags(attrs.visible !== false ? ["prompt"] : []),
917
- zIndex: attrs.zIndex ?? 0,
918
- // Legacy fields
919
- readonly: attrs.readonly ?? false,
920
- visible: attrs.visible ?? true,
921
- hardcoded: attrs.hardcoded ?? false,
922
- template: attrs.template ?? false,
923
- tags: attrs.tags || [],
924
- contentType: attrs.contentType
897
+ systemTags: this.normalizeSystemTags(attrs.systemTags || []),
898
+ zIndex: attrs.zIndex ?? 0
925
899
  };
926
900
  entryMap.set("attributes", normalizedAttrs);
927
901
  }
@@ -1026,7 +1000,7 @@ var MindCache = class {
1026
1000
  if (_processingStack && _processingStack.has(key)) {
1027
1001
  return `{{${key}}}`;
1028
1002
  }
1029
- if (attributes?.systemTags?.includes("ApplyTemplate") || attributes?.systemTags?.includes("template") || attributes?.template) {
1003
+ if (attributes?.systemTags?.includes("ApplyTemplate")) {
1030
1004
  if (typeof value === "string") {
1031
1005
  const stack = _processingStack || /* @__PURE__ */ new Set();
1032
1006
  stack.add(key);
@@ -1040,13 +1014,8 @@ var MindCache = class {
1040
1014
  return {
1041
1015
  type: "text",
1042
1016
  contentTags: [],
1043
- systemTags: ["prompt", "readonly", "protected"],
1044
- zIndex: 999999,
1045
- readonly: true,
1046
- visible: true,
1047
- hardcoded: true,
1048
- template: false,
1049
- tags: []
1017
+ systemTags: ["SystemPrompt", "protected"],
1018
+ zIndex: 999999
1050
1019
  };
1051
1020
  }
1052
1021
  const entryMap = this.rootMap.get(key);
@@ -1071,6 +1040,14 @@ var MindCache = class {
1071
1040
  mergedAttrs.systemTags = this.normalizeSystemTags(mergedAttrs.systemTags);
1072
1041
  }
1073
1042
  entryMap.set("attributes", mergedAttrs);
1043
+ const currentValue = entryMap.get("value");
1044
+ if (mergedAttrs.type === "document" && !(currentValue instanceof Y.Text)) {
1045
+ const strValue = typeof currentValue === "string" ? currentValue : String(currentValue ?? "");
1046
+ entryMap.set("value", new Y.Text(strValue));
1047
+ this.getUndoManager(key);
1048
+ } else if (mergedAttrs.type !== "document" && currentValue instanceof Y.Text) {
1049
+ entryMap.set("value", currentValue.toString());
1050
+ }
1074
1051
  });
1075
1052
  }
1076
1053
  set_value(key, value, attributes) {
@@ -1081,10 +1058,15 @@ var MindCache = class {
1081
1058
  if (existingEntry) {
1082
1059
  const existingAttrs = existingEntry.get("attributes");
1083
1060
  if (existingAttrs?.type === "document") {
1084
- if (typeof value === "string") {
1085
- this._replaceDocumentText(key, value);
1061
+ if (!attributes?.type || attributes.type === "document") {
1062
+ if (typeof value === "string") {
1063
+ this._replaceDocumentText(key, value);
1064
+ }
1065
+ if (attributes) {
1066
+ this.set_attributes(key, attributes);
1067
+ }
1068
+ return;
1086
1069
  }
1087
- return;
1088
1070
  }
1089
1071
  }
1090
1072
  if (!existingEntry && attributes?.type === "document") {
@@ -1100,26 +1082,55 @@ var MindCache = class {
1100
1082
  this.getUndoManager(key);
1101
1083
  this.doc.transact(() => {
1102
1084
  const oldAttributes = isNewEntry ? {
1103
- ...DEFAULT_KEY_ATTRIBUTES,
1104
- contentTags: [],
1105
- systemTags: ["SystemPrompt", "LLMWrite"],
1106
- tags: [],
1107
- zIndex: 0
1085
+ ...DEFAULT_KEY_ATTRIBUTES
1108
1086
  } : entryMap.get("attributes");
1109
1087
  const finalAttributes = attributes ? { ...oldAttributes, ...attributes } : oldAttributes;
1110
1088
  let normalizedAttributes = { ...finalAttributes };
1111
1089
  if (finalAttributes.systemTags) {
1112
1090
  normalizedAttributes.systemTags = this.normalizeSystemTags(finalAttributes.systemTags);
1113
1091
  }
1114
- if (finalAttributes.template) {
1115
- if (!normalizedAttributes.systemTags.includes("template")) {
1116
- normalizedAttributes.systemTags.push("template");
1117
- }
1092
+ let valueToSet = value;
1093
+ if (normalizedAttributes.type === "document" && !(valueToSet instanceof Y.Text)) {
1094
+ valueToSet = new Y.Text(typeof value === "string" ? value : String(value ?? ""));
1095
+ } else if (normalizedAttributes.type !== "document" && valueToSet instanceof Y.Text) {
1096
+ valueToSet = valueToSet.toString();
1118
1097
  }
1119
- entryMap.set("value", value);
1098
+ entryMap.set("value", valueToSet);
1120
1099
  entryMap.set("attributes", normalizedAttributes);
1121
1100
  });
1122
1101
  }
1102
+ /**
1103
+ * LLM-safe method to write a value to a key.
1104
+ * This method:
1105
+ * - Only updates the value, never modifies attributes/systemTags
1106
+ * - Checks LLMWrite permission before writing
1107
+ * - Returns false if key doesn't exist or lacks LLMWrite permission
1108
+ *
1109
+ * Used by create_vercel_ai_tools() to prevent LLMs from escalating privileges.
1110
+ */
1111
+ llm_set_key(key, value) {
1112
+ if (key === "$date" || key === "$time" || key === "$version") {
1113
+ return false;
1114
+ }
1115
+ const entryMap = this.rootMap.get(key);
1116
+ if (!entryMap) {
1117
+ return false;
1118
+ }
1119
+ const attributes = entryMap.get("attributes");
1120
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
1121
+ return false;
1122
+ }
1123
+ if (attributes.type === "document") {
1124
+ if (typeof value === "string") {
1125
+ this._replaceDocumentText(key, value);
1126
+ }
1127
+ return true;
1128
+ }
1129
+ this.doc.transact(() => {
1130
+ entryMap.set("value", value);
1131
+ });
1132
+ return true;
1133
+ }
1123
1134
  delete_key(key) {
1124
1135
  if (key === "$date" || key === "$time") {
1125
1136
  return;
@@ -1564,15 +1575,13 @@ var MindCache = class {
1564
1575
  }
1565
1576
  const attributes = entryMap.get("attributes");
1566
1577
  const value = entryMap.get("value");
1567
- if (attributes?.hardcoded) {
1578
+ if (attributes?.systemTags?.includes("protected")) {
1568
1579
  return;
1569
1580
  }
1570
1581
  lines.push(`### ${key}`);
1571
1582
  const entryType = attributes?.type || "text";
1572
1583
  lines.push(`- **Type**: \`${entryType}\``);
1573
- lines.push(`- **Readonly**: \`${attributes?.readonly ?? false}\``);
1574
- lines.push(`- **Visible**: \`${attributes?.visible ?? true}\``);
1575
- lines.push(`- **Template**: \`${attributes?.template ?? false}\``);
1584
+ lines.push(`- **System Tags**: \`${attributes?.systemTags?.join(", ") || "none"}\``);
1576
1585
  lines.push(`- **Z-Index**: \`${attributes?.zIndex ?? 0}\``);
1577
1586
  if (attributes?.contentTags && attributes.contentTags.length > 0) {
1578
1587
  lines.push(`- **Tags**: \`${attributes.contentTags.join("`, `")}\``);
@@ -1658,16 +1667,11 @@ var MindCache = class {
1658
1667
  }
1659
1668
  continue;
1660
1669
  }
1661
- if (line.startsWith("- **Readonly**:")) {
1662
- currentAttributes.readonly = line.includes("`true`");
1663
- continue;
1664
- }
1665
- if (line.startsWith("- **Visible**:")) {
1666
- currentAttributes.visible = line.includes("`true`");
1667
- continue;
1668
- }
1669
- if (line.startsWith("- **Template**:")) {
1670
- currentAttributes.template = line.includes("`true`");
1670
+ if (line.startsWith("- **System Tags**:")) {
1671
+ const tagsStr = line.match(/`([^`]+)`/)?.[1] || "";
1672
+ if (tagsStr !== "none") {
1673
+ currentAttributes.systemTags = tagsStr.split(", ").filter((t) => t);
1674
+ }
1671
1675
  continue;
1672
1676
  }
1673
1677
  if (line.startsWith("- **Z-Index**:")) {
@@ -1678,7 +1682,6 @@ var MindCache = class {
1678
1682
  if (line.startsWith("- **Tags**:")) {
1679
1683
  const tags = line.match(/`([^`]+)`/g)?.map((t) => t.slice(1, -1)) || [];
1680
1684
  currentAttributes.contentTags = tags;
1681
- currentAttributes.tags = tags;
1682
1685
  continue;
1683
1686
  }
1684
1687
  if (line.startsWith("- **Content Type**:")) {
@@ -1934,8 +1937,12 @@ var MindCache = class {
1934
1937
  /**
1935
1938
  * Generate Vercel AI SDK compatible tools for writable keys.
1936
1939
  * For document type keys, generates additional tools: append_, insert_, edit_
1940
+ *
1941
+ * Security: All tools use llm_set_key internally which:
1942
+ * - Only modifies VALUES, never attributes/systemTags
1943
+ * - Prevents LLMs from escalating privileges
1937
1944
  */
1938
- get_aisdk_tools() {
1945
+ create_vercel_ai_tools() {
1939
1946
  const tools = {};
1940
1947
  for (const [key, val] of this.rootMap) {
1941
1948
  if (key.startsWith("$")) {
@@ -1943,7 +1950,7 @@ var MindCache = class {
1943
1950
  }
1944
1951
  const entryMap = val;
1945
1952
  const attributes = entryMap.get("attributes");
1946
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
1953
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
1947
1954
  if (!isWritable) {
1948
1955
  continue;
1949
1956
  }
@@ -1959,15 +1966,18 @@ var MindCache = class {
1959
1966
  required: ["value"]
1960
1967
  },
1961
1968
  execute: async ({ value }) => {
1962
- if (isDocument) {
1963
- this._replaceDocumentText(key, value);
1964
- } else {
1965
- this.set_value(key, value);
1969
+ const success = this.llm_set_key(key, value);
1970
+ if (success) {
1971
+ return {
1972
+ result: `Successfully wrote "${value}" to ${key}`,
1973
+ key,
1974
+ value
1975
+ };
1966
1976
  }
1967
1977
  return {
1968
- result: `Successfully wrote "${value}" to ${key}`,
1978
+ result: `Failed to write to ${key} - permission denied or key not found`,
1969
1979
  key,
1970
- value
1980
+ error: true
1971
1981
  };
1972
1982
  }
1973
1983
  };
@@ -1982,6 +1992,9 @@ var MindCache = class {
1982
1992
  required: ["text"]
1983
1993
  },
1984
1994
  execute: async ({ text }) => {
1995
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
1996
+ return { result: `Permission denied for ${key}`, key, error: true };
1997
+ }
1985
1998
  const yText = this.get_document(key);
1986
1999
  if (yText) {
1987
2000
  yText.insert(yText.length, text);
@@ -2005,6 +2018,9 @@ var MindCache = class {
2005
2018
  required: ["index", "text"]
2006
2019
  },
2007
2020
  execute: async ({ index, text }) => {
2021
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
2022
+ return { result: `Permission denied for ${key}`, key, error: true };
2023
+ }
2008
2024
  this.insert_text(key, index, text);
2009
2025
  return {
2010
2026
  result: `Successfully inserted text at position ${index} in ${key}`,
@@ -2025,6 +2041,9 @@ var MindCache = class {
2025
2041
  required: ["find", "replace"]
2026
2042
  },
2027
2043
  execute: async ({ find, replace }) => {
2044
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
2045
+ return { result: `Permission denied for ${key}`, key, error: true };
2046
+ }
2028
2047
  const yText = this.get_document(key);
2029
2048
  if (yText) {
2030
2049
  const text = yText.toString();
@@ -2049,6 +2068,12 @@ var MindCache = class {
2049
2068
  }
2050
2069
  return tools;
2051
2070
  }
2071
+ /**
2072
+ * @deprecated Use create_vercel_ai_tools() instead
2073
+ */
2074
+ get_aisdk_tools() {
2075
+ return this.create_vercel_ai_tools();
2076
+ }
2052
2077
  /**
2053
2078
  * Generate a system prompt containing all visible STM keys and their values.
2054
2079
  * Indicates which tools can be used to modify writable keys.
@@ -2061,13 +2086,13 @@ var MindCache = class {
2061
2086
  }
2062
2087
  const entryMap = val;
2063
2088
  const attributes = entryMap.get("attributes");
2064
- const isVisible = attributes?.visible !== false && (attributes?.systemTags?.includes("prompt") || attributes?.systemTags?.includes("SystemPrompt") || !attributes?.systemTags);
2089
+ const isVisible = attributes?.systemTags?.includes("SystemPrompt") || attributes?.systemTags?.includes("LLMRead");
2065
2090
  if (!isVisible) {
2066
2091
  continue;
2067
2092
  }
2068
2093
  const value = this.get_value(key);
2069
2094
  const displayValue = typeof value === "object" ? JSON.stringify(value) : value;
2070
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
2095
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
2071
2096
  const isDocument = attributes?.type === "document";
2072
2097
  const sanitizedKey = this.sanitizeKeyForTool(key);
2073
2098
  if (isWritable) {
@@ -2108,7 +2133,7 @@ var MindCache = class {
2108
2133
  return null;
2109
2134
  }
2110
2135
  const attributes = entryMap.get("attributes");
2111
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
2136
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
2112
2137
  if (!isWritable) {
2113
2138
  return null;
2114
2139
  }
@@ -2223,6 +2248,6 @@ function useMindCache(options) {
2223
2248
  // src/index.ts
2224
2249
  var mindcache = new MindCache();
2225
2250
 
2226
- export { CloudAdapter, DEFAULT_KEY_ATTRIBUTES, IndexedDBAdapter, MindCache, mindcache, useMindCache };
2251
+ export { CloudAdapter, DEFAULT_KEY_ATTRIBUTES, IndexedDBAdapter, MindCache, SystemTagHelpers, mindcache, useMindCache };
2227
2252
  //# sourceMappingURL=index.mjs.map
2228
2253
  //# sourceMappingURL=index.mjs.map