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.
@@ -45,7 +45,7 @@ var init_IndexedDBAdapter = __esm({
45
45
  await this.initDB();
46
46
  await this.load();
47
47
  const listener = () => {
48
- if (this.mindcache && !this.mindcache.isRemoteUpdate()) {
48
+ if (this.mindcache) {
49
49
  this.scheduleSave();
50
50
  }
51
51
  };
@@ -425,15 +425,9 @@ var init_CloudAdapter = __esm({
425
425
  var DEFAULT_KEY_ATTRIBUTES = {
426
426
  type: "text",
427
427
  contentTags: [],
428
- systemTags: ["SystemPrompt", "LLMWrite"],
429
- // visible in system prompt and writable by LLM by default
430
- zIndex: 0,
431
- // Legacy - derived from systemTags
432
- readonly: false,
433
- visible: true,
434
- hardcoded: false,
435
- template: false,
436
- tags: []
428
+ systemTags: [],
429
+ // Keys are private by default - explicitly add SystemPrompt/LLMRead/LLMWrite to enable LLM access
430
+ zIndex: 0
437
431
  };
438
432
 
439
433
  // src/core/MindCache.ts
@@ -449,38 +443,16 @@ var MindCache = class {
449
443
  version = "3.3.2";
450
444
  // Internal flag to prevent sync loops when receiving remote updates
451
445
  // (Less critical with Yjs but kept for API compat)
452
- _isRemoteUpdate = false;
453
446
  normalizeSystemTags(tags) {
454
447
  const normalized = [];
455
- let hasSystemPrompt = false;
456
- let hasLLMRead = false;
457
- let hasLLMWrite = false;
458
- let hasReadonly = false;
448
+ const seen = /* @__PURE__ */ new Set();
459
449
  for (const tag of tags) {
460
- if (tag === "SystemPrompt" || tag === "prompt") {
461
- hasSystemPrompt = true;
462
- } else if (tag === "LLMRead") {
463
- hasLLMRead = true;
464
- } else if (tag === "LLMWrite") {
465
- hasLLMWrite = true;
466
- } else if (tag === "readonly") {
467
- hasReadonly = true;
468
- } else if (tag === "protected") {
469
- normalized.push(tag);
470
- } else if (tag === "ApplyTemplate" || tag === "template") {
471
- normalized.push("ApplyTemplate");
472
- }
473
- }
474
- if (hasSystemPrompt) {
475
- normalized.push("SystemPrompt");
476
- }
477
- if (hasLLMRead) {
478
- normalized.push("LLMRead");
479
- }
480
- if (hasReadonly) {
481
- normalized.push("readonly");
482
- } else if (hasLLMWrite) {
483
- normalized.push("LLMWrite");
450
+ if (["SystemPrompt", "LLMRead", "LLMWrite", "protected", "ApplyTemplate"].includes(tag)) {
451
+ if (!seen.has(tag)) {
452
+ seen.add(tag);
453
+ normalized.push(tag);
454
+ }
455
+ }
484
456
  }
485
457
  return normalized;
486
458
  }
@@ -871,10 +843,6 @@ var MindCache = class {
871
843
  this._idbProvider = null;
872
844
  }
873
845
  }
874
- // Legacy bridge
875
- isRemoteUpdate() {
876
- return false;
877
- }
878
846
  // Serialize state
879
847
  serialize() {
880
848
  const json = {};
@@ -911,16 +879,10 @@ var MindCache = class {
911
879
  const attrs = entry.attributes || {};
912
880
  const normalizedAttrs = {
913
881
  type: attrs.type || "text",
882
+ contentType: attrs.contentType,
914
883
  contentTags: attrs.contentTags || [],
915
- systemTags: attrs.systemTags || this.normalizeSystemTags(attrs.visible !== false ? ["prompt"] : []),
916
- zIndex: attrs.zIndex ?? 0,
917
- // Legacy fields
918
- readonly: attrs.readonly ?? false,
919
- visible: attrs.visible ?? true,
920
- hardcoded: attrs.hardcoded ?? false,
921
- template: attrs.template ?? false,
922
- tags: attrs.tags || [],
923
- contentType: attrs.contentType
884
+ systemTags: this.normalizeSystemTags(attrs.systemTags || []),
885
+ zIndex: attrs.zIndex ?? 0
924
886
  };
925
887
  entryMap.set("attributes", normalizedAttrs);
926
888
  }
@@ -1025,7 +987,7 @@ var MindCache = class {
1025
987
  if (_processingStack && _processingStack.has(key)) {
1026
988
  return `{{${key}}}`;
1027
989
  }
1028
- if (attributes?.systemTags?.includes("ApplyTemplate") || attributes?.systemTags?.includes("template") || attributes?.template) {
990
+ if (attributes?.systemTags?.includes("ApplyTemplate")) {
1029
991
  if (typeof value === "string") {
1030
992
  const stack = _processingStack || /* @__PURE__ */ new Set();
1031
993
  stack.add(key);
@@ -1039,13 +1001,8 @@ var MindCache = class {
1039
1001
  return {
1040
1002
  type: "text",
1041
1003
  contentTags: [],
1042
- systemTags: ["prompt", "readonly", "protected"],
1043
- zIndex: 999999,
1044
- readonly: true,
1045
- visible: true,
1046
- hardcoded: true,
1047
- template: false,
1048
- tags: []
1004
+ systemTags: ["SystemPrompt", "protected"],
1005
+ zIndex: 999999
1049
1006
  };
1050
1007
  }
1051
1008
  const entryMap = this.rootMap.get(key);
@@ -1070,6 +1027,14 @@ var MindCache = class {
1070
1027
  mergedAttrs.systemTags = this.normalizeSystemTags(mergedAttrs.systemTags);
1071
1028
  }
1072
1029
  entryMap.set("attributes", mergedAttrs);
1030
+ const currentValue = entryMap.get("value");
1031
+ if (mergedAttrs.type === "document" && !(currentValue instanceof Y.Text)) {
1032
+ const strValue = typeof currentValue === "string" ? currentValue : String(currentValue ?? "");
1033
+ entryMap.set("value", new Y.Text(strValue));
1034
+ this.getUndoManager(key);
1035
+ } else if (mergedAttrs.type !== "document" && currentValue instanceof Y.Text) {
1036
+ entryMap.set("value", currentValue.toString());
1037
+ }
1073
1038
  });
1074
1039
  }
1075
1040
  set_value(key, value, attributes) {
@@ -1080,10 +1045,15 @@ var MindCache = class {
1080
1045
  if (existingEntry) {
1081
1046
  const existingAttrs = existingEntry.get("attributes");
1082
1047
  if (existingAttrs?.type === "document") {
1083
- if (typeof value === "string") {
1084
- this._replaceDocumentText(key, value);
1048
+ if (!attributes?.type || attributes.type === "document") {
1049
+ if (typeof value === "string") {
1050
+ this._replaceDocumentText(key, value);
1051
+ }
1052
+ if (attributes) {
1053
+ this.set_attributes(key, attributes);
1054
+ }
1055
+ return;
1085
1056
  }
1086
- return;
1087
1057
  }
1088
1058
  }
1089
1059
  if (!existingEntry && attributes?.type === "document") {
@@ -1099,26 +1069,55 @@ var MindCache = class {
1099
1069
  this.getUndoManager(key);
1100
1070
  this.doc.transact(() => {
1101
1071
  const oldAttributes = isNewEntry ? {
1102
- ...DEFAULT_KEY_ATTRIBUTES,
1103
- contentTags: [],
1104
- systemTags: ["SystemPrompt", "LLMWrite"],
1105
- tags: [],
1106
- zIndex: 0
1072
+ ...DEFAULT_KEY_ATTRIBUTES
1107
1073
  } : entryMap.get("attributes");
1108
1074
  const finalAttributes = attributes ? { ...oldAttributes, ...attributes } : oldAttributes;
1109
1075
  let normalizedAttributes = { ...finalAttributes };
1110
1076
  if (finalAttributes.systemTags) {
1111
1077
  normalizedAttributes.systemTags = this.normalizeSystemTags(finalAttributes.systemTags);
1112
1078
  }
1113
- if (finalAttributes.template) {
1114
- if (!normalizedAttributes.systemTags.includes("template")) {
1115
- normalizedAttributes.systemTags.push("template");
1116
- }
1079
+ let valueToSet = value;
1080
+ if (normalizedAttributes.type === "document" && !(valueToSet instanceof Y.Text)) {
1081
+ valueToSet = new Y.Text(typeof value === "string" ? value : String(value ?? ""));
1082
+ } else if (normalizedAttributes.type !== "document" && valueToSet instanceof Y.Text) {
1083
+ valueToSet = valueToSet.toString();
1117
1084
  }
1118
- entryMap.set("value", value);
1085
+ entryMap.set("value", valueToSet);
1119
1086
  entryMap.set("attributes", normalizedAttributes);
1120
1087
  });
1121
1088
  }
1089
+ /**
1090
+ * LLM-safe method to write a value to a key.
1091
+ * This method:
1092
+ * - Only updates the value, never modifies attributes/systemTags
1093
+ * - Checks LLMWrite permission before writing
1094
+ * - Returns false if key doesn't exist or lacks LLMWrite permission
1095
+ *
1096
+ * Used by create_vercel_ai_tools() to prevent LLMs from escalating privileges.
1097
+ */
1098
+ llm_set_key(key, value) {
1099
+ if (key === "$date" || key === "$time" || key === "$version") {
1100
+ return false;
1101
+ }
1102
+ const entryMap = this.rootMap.get(key);
1103
+ if (!entryMap) {
1104
+ return false;
1105
+ }
1106
+ const attributes = entryMap.get("attributes");
1107
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
1108
+ return false;
1109
+ }
1110
+ if (attributes.type === "document") {
1111
+ if (typeof value === "string") {
1112
+ this._replaceDocumentText(key, value);
1113
+ }
1114
+ return true;
1115
+ }
1116
+ this.doc.transact(() => {
1117
+ entryMap.set("value", value);
1118
+ });
1119
+ return true;
1120
+ }
1122
1121
  delete_key(key) {
1123
1122
  if (key === "$date" || key === "$time") {
1124
1123
  return;
@@ -1563,15 +1562,13 @@ var MindCache = class {
1563
1562
  }
1564
1563
  const attributes = entryMap.get("attributes");
1565
1564
  const value = entryMap.get("value");
1566
- if (attributes?.hardcoded) {
1565
+ if (attributes?.systemTags?.includes("protected")) {
1567
1566
  return;
1568
1567
  }
1569
1568
  lines.push(`### ${key}`);
1570
1569
  const entryType = attributes?.type || "text";
1571
1570
  lines.push(`- **Type**: \`${entryType}\``);
1572
- lines.push(`- **Readonly**: \`${attributes?.readonly ?? false}\``);
1573
- lines.push(`- **Visible**: \`${attributes?.visible ?? true}\``);
1574
- lines.push(`- **Template**: \`${attributes?.template ?? false}\``);
1571
+ lines.push(`- **System Tags**: \`${attributes?.systemTags?.join(", ") || "none"}\``);
1575
1572
  lines.push(`- **Z-Index**: \`${attributes?.zIndex ?? 0}\``);
1576
1573
  if (attributes?.contentTags && attributes.contentTags.length > 0) {
1577
1574
  lines.push(`- **Tags**: \`${attributes.contentTags.join("`, `")}\``);
@@ -1657,16 +1654,11 @@ var MindCache = class {
1657
1654
  }
1658
1655
  continue;
1659
1656
  }
1660
- if (line.startsWith("- **Readonly**:")) {
1661
- currentAttributes.readonly = line.includes("`true`");
1662
- continue;
1663
- }
1664
- if (line.startsWith("- **Visible**:")) {
1665
- currentAttributes.visible = line.includes("`true`");
1666
- continue;
1667
- }
1668
- if (line.startsWith("- **Template**:")) {
1669
- currentAttributes.template = line.includes("`true`");
1657
+ if (line.startsWith("- **System Tags**:")) {
1658
+ const tagsStr = line.match(/`([^`]+)`/)?.[1] || "";
1659
+ if (tagsStr !== "none") {
1660
+ currentAttributes.systemTags = tagsStr.split(", ").filter((t) => t);
1661
+ }
1670
1662
  continue;
1671
1663
  }
1672
1664
  if (line.startsWith("- **Z-Index**:")) {
@@ -1677,7 +1669,6 @@ var MindCache = class {
1677
1669
  if (line.startsWith("- **Tags**:")) {
1678
1670
  const tags = line.match(/`([^`]+)`/g)?.map((t) => t.slice(1, -1)) || [];
1679
1671
  currentAttributes.contentTags = tags;
1680
- currentAttributes.tags = tags;
1681
1672
  continue;
1682
1673
  }
1683
1674
  if (line.startsWith("- **Content Type**:")) {
@@ -1933,8 +1924,12 @@ var MindCache = class {
1933
1924
  /**
1934
1925
  * Generate Vercel AI SDK compatible tools for writable keys.
1935
1926
  * For document type keys, generates additional tools: append_, insert_, edit_
1927
+ *
1928
+ * Security: All tools use llm_set_key internally which:
1929
+ * - Only modifies VALUES, never attributes/systemTags
1930
+ * - Prevents LLMs from escalating privileges
1936
1931
  */
1937
- get_aisdk_tools() {
1932
+ create_vercel_ai_tools() {
1938
1933
  const tools = {};
1939
1934
  for (const [key, val] of this.rootMap) {
1940
1935
  if (key.startsWith("$")) {
@@ -1942,7 +1937,7 @@ var MindCache = class {
1942
1937
  }
1943
1938
  const entryMap = val;
1944
1939
  const attributes = entryMap.get("attributes");
1945
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
1940
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
1946
1941
  if (!isWritable) {
1947
1942
  continue;
1948
1943
  }
@@ -1958,15 +1953,18 @@ var MindCache = class {
1958
1953
  required: ["value"]
1959
1954
  },
1960
1955
  execute: async ({ value }) => {
1961
- if (isDocument) {
1962
- this._replaceDocumentText(key, value);
1963
- } else {
1964
- this.set_value(key, value);
1956
+ const success = this.llm_set_key(key, value);
1957
+ if (success) {
1958
+ return {
1959
+ result: `Successfully wrote "${value}" to ${key}`,
1960
+ key,
1961
+ value
1962
+ };
1965
1963
  }
1966
1964
  return {
1967
- result: `Successfully wrote "${value}" to ${key}`,
1965
+ result: `Failed to write to ${key} - permission denied or key not found`,
1968
1966
  key,
1969
- value
1967
+ error: true
1970
1968
  };
1971
1969
  }
1972
1970
  };
@@ -1981,6 +1979,9 @@ var MindCache = class {
1981
1979
  required: ["text"]
1982
1980
  },
1983
1981
  execute: async ({ text }) => {
1982
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
1983
+ return { result: `Permission denied for ${key}`, key, error: true };
1984
+ }
1984
1985
  const yText = this.get_document(key);
1985
1986
  if (yText) {
1986
1987
  yText.insert(yText.length, text);
@@ -2004,6 +2005,9 @@ var MindCache = class {
2004
2005
  required: ["index", "text"]
2005
2006
  },
2006
2007
  execute: async ({ index, text }) => {
2008
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
2009
+ return { result: `Permission denied for ${key}`, key, error: true };
2010
+ }
2007
2011
  this.insert_text(key, index, text);
2008
2012
  return {
2009
2013
  result: `Successfully inserted text at position ${index} in ${key}`,
@@ -2024,6 +2028,9 @@ var MindCache = class {
2024
2028
  required: ["find", "replace"]
2025
2029
  },
2026
2030
  execute: async ({ find, replace }) => {
2031
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
2032
+ return { result: `Permission denied for ${key}`, key, error: true };
2033
+ }
2027
2034
  const yText = this.get_document(key);
2028
2035
  if (yText) {
2029
2036
  const text = yText.toString();
@@ -2048,6 +2055,12 @@ var MindCache = class {
2048
2055
  }
2049
2056
  return tools;
2050
2057
  }
2058
+ /**
2059
+ * @deprecated Use create_vercel_ai_tools() instead
2060
+ */
2061
+ get_aisdk_tools() {
2062
+ return this.create_vercel_ai_tools();
2063
+ }
2051
2064
  /**
2052
2065
  * Generate a system prompt containing all visible STM keys and their values.
2053
2066
  * Indicates which tools can be used to modify writable keys.
@@ -2060,13 +2073,13 @@ var MindCache = class {
2060
2073
  }
2061
2074
  const entryMap = val;
2062
2075
  const attributes = entryMap.get("attributes");
2063
- const isVisible = attributes?.visible !== false && (attributes?.systemTags?.includes("prompt") || attributes?.systemTags?.includes("SystemPrompt") || !attributes?.systemTags);
2076
+ const isVisible = attributes?.systemTags?.includes("SystemPrompt") || attributes?.systemTags?.includes("LLMRead");
2064
2077
  if (!isVisible) {
2065
2078
  continue;
2066
2079
  }
2067
2080
  const value = this.get_value(key);
2068
2081
  const displayValue = typeof value === "object" ? JSON.stringify(value) : value;
2069
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
2082
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
2070
2083
  const isDocument = attributes?.type === "document";
2071
2084
  const sanitizedKey = this.sanitizeKeyForTool(key);
2072
2085
  if (isWritable) {
@@ -2107,7 +2120,7 @@ var MindCache = class {
2107
2120
  return null;
2108
2121
  }
2109
2122
  const attributes = entryMap.get("attributes");
2110
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
2123
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
2111
2124
  if (!isWritable) {
2112
2125
  return null;
2113
2126
  }