mindcache 3.4.1 → 3.4.3

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
@@ -178,6 +178,7 @@ var init_CloudAdapter = __esm({
178
178
  RECONNECT_DELAY = 1e3;
179
179
  MAX_RECONNECT_DELAY = 3e4;
180
180
  CloudAdapter = class {
181
+ // Track if initial sync is complete
181
182
  constructor(config) {
182
183
  this.config = config;
183
184
  if (!config.baseUrl) {
@@ -197,6 +198,7 @@ var init_CloudAdapter = __esm({
197
198
  token = null;
198
199
  handleOnline = null;
199
200
  handleOffline = null;
201
+ _synced = false;
200
202
  /** Browser network status - instantly updated via navigator.onLine */
201
203
  get isOnline() {
202
204
  return this._isOnline;
@@ -379,10 +381,14 @@ var init_CloudAdapter = __esm({
379
381
  const encoder = encoding.createEncoder();
380
382
  const decoder = decoding.createDecoder(new Uint8Array(event.data));
381
383
  if (this.mindcache) {
382
- syncProtocol.readSyncMessage(decoder, encoder, this.mindcache.doc, this);
384
+ const messageType = syncProtocol.readSyncMessage(decoder, encoder, this.mindcache.doc, this);
383
385
  if (encoding.length(encoder) > 0) {
384
386
  this.sendBinary(encoding.toUint8Array(encoder));
385
387
  }
388
+ if (!this._synced && (messageType === 1 || messageType === 2)) {
389
+ this._synced = true;
390
+ this.emit("synced");
391
+ }
386
392
  }
387
393
  }
388
394
  } catch (error) {
@@ -426,15 +432,21 @@ var init_CloudAdapter = __esm({
426
432
  var DEFAULT_KEY_ATTRIBUTES = {
427
433
  type: "text",
428
434
  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: []
435
+ systemTags: [],
436
+ // Keys are private by default - explicitly add SystemPrompt/LLMRead/LLMWrite to enable LLM access
437
+ zIndex: 0
438
+ };
439
+ var SystemTagHelpers = {
440
+ /** Check if key is writable by LLM */
441
+ isLLMWritable: (attrs) => attrs.systemTags.includes("LLMWrite"),
442
+ /** Check if key is readable by LLM (in context or via tools) */
443
+ isLLMReadable: (attrs) => attrs.systemTags.includes("SystemPrompt") || attrs.systemTags.includes("LLMRead"),
444
+ /** Check if key is included in system prompt */
445
+ isInSystemPrompt: (attrs) => attrs.systemTags.includes("SystemPrompt"),
446
+ /** Check if key is protected from deletion */
447
+ isProtected: (attrs) => attrs.systemTags.includes("protected"),
448
+ /** Check if key uses template injection */
449
+ hasTemplateInjection: (attrs) => attrs.systemTags.includes("ApplyTemplate")
438
450
  };
439
451
 
440
452
  // src/core/MindCache.ts
@@ -452,35 +464,14 @@ var MindCache = class {
452
464
  // (Less critical with Yjs but kept for API compat)
453
465
  normalizeSystemTags(tags) {
454
466
  const normalized = [];
455
- let hasSystemPrompt = false;
456
- let hasLLMRead = false;
457
- let hasLLMWrite = false;
458
- let hasReadonly = false;
467
+ const seen = /* @__PURE__ */ new Set();
459
468
  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");
469
+ if (["SystemPrompt", "LLMRead", "LLMWrite", "protected", "ApplyTemplate"].includes(tag)) {
470
+ if (!seen.has(tag)) {
471
+ seen.add(tag);
472
+ normalized.push(tag);
473
+ }
474
+ }
484
475
  }
485
476
  return normalized;
486
477
  }
@@ -504,7 +495,7 @@ var MindCache = class {
504
495
  _historyOptions = { maxEntries: 100, snapshotInterval: 10 };
505
496
  _historyEnabled = false;
506
497
  constructor(options) {
507
- this.doc = new Y.Doc();
498
+ this.doc = options?.doc || new Y.Doc();
508
499
  this.rootMap = this.doc.getMap("mindcache");
509
500
  this.rootMap.observeDeep((events) => {
510
501
  const keysAffected = /* @__PURE__ */ new Set();
@@ -907,16 +898,10 @@ var MindCache = class {
907
898
  const attrs = entry.attributes || {};
908
899
  const normalizedAttrs = {
909
900
  type: attrs.type || "text",
901
+ contentType: attrs.contentType,
910
902
  contentTags: attrs.contentTags || [],
911
- systemTags: attrs.systemTags || this.normalizeSystemTags(attrs.visible !== false ? ["prompt"] : []),
912
- zIndex: attrs.zIndex ?? 0,
913
- // Legacy fields
914
- readonly: attrs.readonly ?? false,
915
- visible: attrs.visible ?? true,
916
- hardcoded: attrs.hardcoded ?? false,
917
- template: attrs.template ?? false,
918
- tags: attrs.tags || [],
919
- contentType: attrs.contentType
903
+ systemTags: this.normalizeSystemTags(attrs.systemTags || []),
904
+ zIndex: attrs.zIndex ?? 0
920
905
  };
921
906
  entryMap.set("attributes", normalizedAttrs);
922
907
  }
@@ -1021,7 +1006,7 @@ var MindCache = class {
1021
1006
  if (_processingStack && _processingStack.has(key)) {
1022
1007
  return `{{${key}}}`;
1023
1008
  }
1024
- if (attributes?.systemTags?.includes("ApplyTemplate") || attributes?.systemTags?.includes("template") || attributes?.template) {
1009
+ if (attributes?.systemTags?.includes("ApplyTemplate")) {
1025
1010
  if (typeof value === "string") {
1026
1011
  const stack = _processingStack || /* @__PURE__ */ new Set();
1027
1012
  stack.add(key);
@@ -1035,13 +1020,8 @@ var MindCache = class {
1035
1020
  return {
1036
1021
  type: "text",
1037
1022
  contentTags: [],
1038
- systemTags: ["prompt", "readonly", "protected"],
1039
- zIndex: 999999,
1040
- readonly: true,
1041
- visible: true,
1042
- hardcoded: true,
1043
- template: false,
1044
- tags: []
1023
+ systemTags: ["SystemPrompt", "protected"],
1024
+ zIndex: 999999
1045
1025
  };
1046
1026
  }
1047
1027
  const entryMap = this.rootMap.get(key);
@@ -1108,22 +1088,13 @@ var MindCache = class {
1108
1088
  this.getUndoManager(key);
1109
1089
  this.doc.transact(() => {
1110
1090
  const oldAttributes = isNewEntry ? {
1111
- ...DEFAULT_KEY_ATTRIBUTES,
1112
- contentTags: [],
1113
- systemTags: ["SystemPrompt", "LLMWrite"],
1114
- tags: [],
1115
- zIndex: 0
1091
+ ...DEFAULT_KEY_ATTRIBUTES
1116
1092
  } : entryMap.get("attributes");
1117
1093
  const finalAttributes = attributes ? { ...oldAttributes, ...attributes } : oldAttributes;
1118
1094
  let normalizedAttributes = { ...finalAttributes };
1119
1095
  if (finalAttributes.systemTags) {
1120
1096
  normalizedAttributes.systemTags = this.normalizeSystemTags(finalAttributes.systemTags);
1121
1097
  }
1122
- if (finalAttributes.template) {
1123
- if (!normalizedAttributes.systemTags.includes("template")) {
1124
- normalizedAttributes.systemTags.push("template");
1125
- }
1126
- }
1127
1098
  let valueToSet = value;
1128
1099
  if (normalizedAttributes.type === "document" && !(valueToSet instanceof Y.Text)) {
1129
1100
  valueToSet = new Y.Text(typeof value === "string" ? value : String(value ?? ""));
@@ -1134,6 +1105,38 @@ var MindCache = class {
1134
1105
  entryMap.set("attributes", normalizedAttributes);
1135
1106
  });
1136
1107
  }
1108
+ /**
1109
+ * LLM-safe method to write a value to a key.
1110
+ * This method:
1111
+ * - Only updates the value, never modifies attributes/systemTags
1112
+ * - Checks LLMWrite permission before writing
1113
+ * - Returns false if key doesn't exist or lacks LLMWrite permission
1114
+ *
1115
+ * Used by create_vercel_ai_tools() to prevent LLMs from escalating privileges.
1116
+ */
1117
+ llm_set_key(key, value) {
1118
+ if (key === "$date" || key === "$time" || key === "$version") {
1119
+ return false;
1120
+ }
1121
+ const entryMap = this.rootMap.get(key);
1122
+ if (!entryMap) {
1123
+ return false;
1124
+ }
1125
+ const attributes = entryMap.get("attributes");
1126
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
1127
+ return false;
1128
+ }
1129
+ if (attributes.type === "document") {
1130
+ if (typeof value === "string") {
1131
+ this._replaceDocumentText(key, value);
1132
+ }
1133
+ return true;
1134
+ }
1135
+ this.doc.transact(() => {
1136
+ entryMap.set("value", value);
1137
+ });
1138
+ return true;
1139
+ }
1137
1140
  delete_key(key) {
1138
1141
  if (key === "$date" || key === "$time") {
1139
1142
  return;
@@ -1578,15 +1581,13 @@ var MindCache = class {
1578
1581
  }
1579
1582
  const attributes = entryMap.get("attributes");
1580
1583
  const value = entryMap.get("value");
1581
- if (attributes?.hardcoded) {
1584
+ if (attributes?.systemTags?.includes("protected")) {
1582
1585
  return;
1583
1586
  }
1584
1587
  lines.push(`### ${key}`);
1585
1588
  const entryType = attributes?.type || "text";
1586
1589
  lines.push(`- **Type**: \`${entryType}\``);
1587
- lines.push(`- **Readonly**: \`${attributes?.readonly ?? false}\``);
1588
- lines.push(`- **Visible**: \`${attributes?.visible ?? true}\``);
1589
- lines.push(`- **Template**: \`${attributes?.template ?? false}\``);
1590
+ lines.push(`- **System Tags**: \`${attributes?.systemTags?.join(", ") || "none"}\``);
1590
1591
  lines.push(`- **Z-Index**: \`${attributes?.zIndex ?? 0}\``);
1591
1592
  if (attributes?.contentTags && attributes.contentTags.length > 0) {
1592
1593
  lines.push(`- **Tags**: \`${attributes.contentTags.join("`, `")}\``);
@@ -1616,7 +1617,10 @@ var MindCache = class {
1616
1617
  }
1617
1618
  lines.push("```");
1618
1619
  } else {
1619
- lines.push(`- **Value**: ${value}`);
1620
+ lines.push("- **Value**:");
1621
+ lines.push("```");
1622
+ lines.push(String(value));
1623
+ lines.push("```");
1620
1624
  }
1621
1625
  lines.push("");
1622
1626
  });
@@ -1651,7 +1655,7 @@ var MindCache = class {
1651
1655
  for (const line of lines) {
1652
1656
  if (line.startsWith("### ") && !line.startsWith("### Appendix")) {
1653
1657
  if (currentKey && currentValue !== null) {
1654
- this.set_value(currentKey, currentValue, currentAttributes);
1658
+ this.set_value(currentKey, currentValue.trim(), currentAttributes);
1655
1659
  }
1656
1660
  currentKey = line.substring(4).trim();
1657
1661
  currentAttributes = {};
@@ -1672,16 +1676,11 @@ var MindCache = class {
1672
1676
  }
1673
1677
  continue;
1674
1678
  }
1675
- if (line.startsWith("- **Readonly**:")) {
1676
- currentAttributes.readonly = line.includes("`true`");
1677
- continue;
1678
- }
1679
- if (line.startsWith("- **Visible**:")) {
1680
- currentAttributes.visible = line.includes("`true`");
1681
- continue;
1682
- }
1683
- if (line.startsWith("- **Template**:")) {
1684
- currentAttributes.template = line.includes("`true`");
1679
+ if (line.startsWith("- **System Tags**:")) {
1680
+ const tagsStr = line.match(/`([^`]+)`/)?.[1] || "";
1681
+ if (tagsStr !== "none") {
1682
+ currentAttributes.systemTags = tagsStr.split(", ").filter((t) => t);
1683
+ }
1685
1684
  continue;
1686
1685
  }
1687
1686
  if (line.startsWith("- **Z-Index**:")) {
@@ -1692,7 +1691,6 @@ var MindCache = class {
1692
1691
  if (line.startsWith("- **Tags**:")) {
1693
1692
  const tags = line.match(/`([^`]+)`/g)?.map((t) => t.slice(1, -1)) || [];
1694
1693
  currentAttributes.contentTags = tags;
1695
- currentAttributes.tags = tags;
1696
1694
  continue;
1697
1695
  }
1698
1696
  if (line.startsWith("- **Content Type**:")) {
@@ -1700,10 +1698,24 @@ var MindCache = class {
1700
1698
  continue;
1701
1699
  }
1702
1700
  if (line.startsWith("- **Value**:") && !line.includes("[See Appendix")) {
1703
- currentValue = line.substring(12).trim();
1701
+ const afterValue = line.substring(12).trim();
1702
+ if (afterValue === "") {
1703
+ currentValue = "";
1704
+ } else if (afterValue === "```" || afterValue === "```json") {
1705
+ inCodeBlock = true;
1706
+ codeBlockContent = [];
1707
+ currentValue = "";
1708
+ } else if (afterValue.startsWith("```")) {
1709
+ inCodeBlock = true;
1710
+ codeBlockContent = [afterValue.substring(3)];
1711
+ currentValue = "";
1712
+ } else {
1713
+ currentValue = afterValue;
1714
+ }
1704
1715
  continue;
1705
1716
  }
1706
- if (line === "```json" || line === "```") {
1717
+ const trimmedLine = line.trim();
1718
+ if (trimmedLine === "```json" || trimmedLine === "```") {
1707
1719
  if (inCodeBlock) {
1708
1720
  inCodeBlock = false;
1709
1721
  if (currentKey && codeBlockContent.length > 0) {
@@ -1712,15 +1724,27 @@ var MindCache = class {
1712
1724
  codeBlockContent = [];
1713
1725
  } else {
1714
1726
  inCodeBlock = true;
1727
+ codeBlockContent = [];
1715
1728
  }
1716
1729
  continue;
1717
1730
  }
1718
1731
  if (inCodeBlock) {
1719
1732
  codeBlockContent.push(line);
1733
+ } else if (currentKey && currentValue !== null) {
1734
+ currentValue += "\n" + line;
1720
1735
  }
1721
1736
  }
1722
1737
  if (currentKey && currentValue !== null) {
1723
- this.set_value(currentKey, currentValue, currentAttributes);
1738
+ this.set_value(currentKey, currentValue.trim(), currentAttributes);
1739
+ }
1740
+ const hasParsedKeys = lines.some((line) => line.startsWith("### ") && !line.startsWith("### Appendix"));
1741
+ if (!hasParsedKeys && markdown.trim().length > 0) {
1742
+ this.set_value("imported_content", markdown.trim(), {
1743
+ type: "text",
1744
+ systemTags: ["SystemPrompt", "LLMWrite"],
1745
+ // Default assumptions
1746
+ zIndex: 0
1747
+ });
1724
1748
  }
1725
1749
  }
1726
1750
  /**
@@ -1948,8 +1972,12 @@ var MindCache = class {
1948
1972
  /**
1949
1973
  * Generate Vercel AI SDK compatible tools for writable keys.
1950
1974
  * For document type keys, generates additional tools: append_, insert_, edit_
1975
+ *
1976
+ * Security: All tools use llm_set_key internally which:
1977
+ * - Only modifies VALUES, never attributes/systemTags
1978
+ * - Prevents LLMs from escalating privileges
1951
1979
  */
1952
- get_aisdk_tools() {
1980
+ create_vercel_ai_tools() {
1953
1981
  const tools = {};
1954
1982
  for (const [key, val] of this.rootMap) {
1955
1983
  if (key.startsWith("$")) {
@@ -1957,7 +1985,7 @@ var MindCache = class {
1957
1985
  }
1958
1986
  const entryMap = val;
1959
1987
  const attributes = entryMap.get("attributes");
1960
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
1988
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
1961
1989
  if (!isWritable) {
1962
1990
  continue;
1963
1991
  }
@@ -1973,15 +2001,18 @@ var MindCache = class {
1973
2001
  required: ["value"]
1974
2002
  },
1975
2003
  execute: async ({ value }) => {
1976
- if (isDocument) {
1977
- this._replaceDocumentText(key, value);
1978
- } else {
1979
- this.set_value(key, value);
2004
+ const success = this.llm_set_key(key, value);
2005
+ if (success) {
2006
+ return {
2007
+ result: `Successfully wrote "${value}" to ${key}`,
2008
+ key,
2009
+ value
2010
+ };
1980
2011
  }
1981
2012
  return {
1982
- result: `Successfully wrote "${value}" to ${key}`,
2013
+ result: `Failed to write to ${key} - permission denied or key not found`,
1983
2014
  key,
1984
- value
2015
+ error: true
1985
2016
  };
1986
2017
  }
1987
2018
  };
@@ -1996,6 +2027,9 @@ var MindCache = class {
1996
2027
  required: ["text"]
1997
2028
  },
1998
2029
  execute: async ({ text }) => {
2030
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
2031
+ return { result: `Permission denied for ${key}`, key, error: true };
2032
+ }
1999
2033
  const yText = this.get_document(key);
2000
2034
  if (yText) {
2001
2035
  yText.insert(yText.length, text);
@@ -2019,6 +2053,9 @@ var MindCache = class {
2019
2053
  required: ["index", "text"]
2020
2054
  },
2021
2055
  execute: async ({ index, text }) => {
2056
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
2057
+ return { result: `Permission denied for ${key}`, key, error: true };
2058
+ }
2022
2059
  this.insert_text(key, index, text);
2023
2060
  return {
2024
2061
  result: `Successfully inserted text at position ${index} in ${key}`,
@@ -2039,6 +2076,9 @@ var MindCache = class {
2039
2076
  required: ["find", "replace"]
2040
2077
  },
2041
2078
  execute: async ({ find, replace }) => {
2079
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
2080
+ return { result: `Permission denied for ${key}`, key, error: true };
2081
+ }
2042
2082
  const yText = this.get_document(key);
2043
2083
  if (yText) {
2044
2084
  const text = yText.toString();
@@ -2063,6 +2103,12 @@ var MindCache = class {
2063
2103
  }
2064
2104
  return tools;
2065
2105
  }
2106
+ /**
2107
+ * @deprecated Use create_vercel_ai_tools() instead
2108
+ */
2109
+ get_aisdk_tools() {
2110
+ return this.create_vercel_ai_tools();
2111
+ }
2066
2112
  /**
2067
2113
  * Generate a system prompt containing all visible STM keys and their values.
2068
2114
  * Indicates which tools can be used to modify writable keys.
@@ -2075,13 +2121,13 @@ var MindCache = class {
2075
2121
  }
2076
2122
  const entryMap = val;
2077
2123
  const attributes = entryMap.get("attributes");
2078
- const isVisible = attributes?.visible !== false && (attributes?.systemTags?.includes("prompt") || attributes?.systemTags?.includes("SystemPrompt") || !attributes?.systemTags);
2124
+ const isVisible = attributes?.systemTags?.includes("SystemPrompt") || attributes?.systemTags?.includes("LLMRead");
2079
2125
  if (!isVisible) {
2080
2126
  continue;
2081
2127
  }
2082
2128
  const value = this.get_value(key);
2083
2129
  const displayValue = typeof value === "object" ? JSON.stringify(value) : value;
2084
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
2130
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
2085
2131
  const isDocument = attributes?.type === "document";
2086
2132
  const sanitizedKey = this.sanitizeKeyForTool(key);
2087
2133
  if (isWritable) {
@@ -2122,7 +2168,7 @@ var MindCache = class {
2122
2168
  return null;
2123
2169
  }
2124
2170
  const attributes = entryMap.get("attributes");
2125
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
2171
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
2126
2172
  if (!isWritable) {
2127
2173
  return null;
2128
2174
  }
@@ -2237,6 +2283,6 @@ function useMindCache(options) {
2237
2283
  // src/index.ts
2238
2284
  var mindcache = new MindCache();
2239
2285
 
2240
- export { CloudAdapter, DEFAULT_KEY_ATTRIBUTES, IndexedDBAdapter, MindCache, mindcache, useMindCache };
2286
+ export { CloudAdapter, DEFAULT_KEY_ATTRIBUTES, IndexedDBAdapter, MindCache, SystemTagHelpers, mindcache, useMindCache };
2241
2287
  //# sourceMappingURL=index.mjs.map
2242
2288
  //# sourceMappingURL=index.mjs.map