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.
@@ -177,6 +177,7 @@ var init_CloudAdapter = __esm({
177
177
  RECONNECT_DELAY = 1e3;
178
178
  MAX_RECONNECT_DELAY = 3e4;
179
179
  CloudAdapter = class {
180
+ // Track if initial sync is complete
180
181
  constructor(config) {
181
182
  this.config = config;
182
183
  if (!config.baseUrl) {
@@ -196,6 +197,7 @@ var init_CloudAdapter = __esm({
196
197
  token = null;
197
198
  handleOnline = null;
198
199
  handleOffline = null;
200
+ _synced = false;
199
201
  /** Browser network status - instantly updated via navigator.onLine */
200
202
  get isOnline() {
201
203
  return this._isOnline;
@@ -378,10 +380,14 @@ var init_CloudAdapter = __esm({
378
380
  const encoder = encoding.createEncoder();
379
381
  const decoder = decoding.createDecoder(new Uint8Array(event.data));
380
382
  if (this.mindcache) {
381
- syncProtocol.readSyncMessage(decoder, encoder, this.mindcache.doc, this);
383
+ const messageType = syncProtocol.readSyncMessage(decoder, encoder, this.mindcache.doc, this);
382
384
  if (encoding.length(encoder) > 0) {
383
385
  this.sendBinary(encoding.toUint8Array(encoder));
384
386
  }
387
+ if (!this._synced && (messageType === 1 || messageType === 2)) {
388
+ this._synced = true;
389
+ this.emit("synced");
390
+ }
385
391
  }
386
392
  }
387
393
  } catch (error) {
@@ -425,15 +431,9 @@ var init_CloudAdapter = __esm({
425
431
  var DEFAULT_KEY_ATTRIBUTES = {
426
432
  type: "text",
427
433
  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: []
434
+ systemTags: [],
435
+ // Keys are private by default - explicitly add SystemPrompt/LLMRead/LLMWrite to enable LLM access
436
+ zIndex: 0
437
437
  };
438
438
 
439
439
  // src/core/MindCache.ts
@@ -451,35 +451,14 @@ var MindCache = class {
451
451
  // (Less critical with Yjs but kept for API compat)
452
452
  normalizeSystemTags(tags) {
453
453
  const normalized = [];
454
- let hasSystemPrompt = false;
455
- let hasLLMRead = false;
456
- let hasLLMWrite = false;
457
- let hasReadonly = false;
454
+ const seen = /* @__PURE__ */ new Set();
458
455
  for (const tag of tags) {
459
- if (tag === "SystemPrompt" || tag === "prompt") {
460
- hasSystemPrompt = true;
461
- } else if (tag === "LLMRead") {
462
- hasLLMRead = true;
463
- } else if (tag === "LLMWrite") {
464
- hasLLMWrite = true;
465
- } else if (tag === "readonly") {
466
- hasReadonly = true;
467
- } else if (tag === "protected") {
468
- normalized.push(tag);
469
- } else if (tag === "ApplyTemplate" || tag === "template") {
470
- normalized.push("ApplyTemplate");
471
- }
472
- }
473
- if (hasSystemPrompt) {
474
- normalized.push("SystemPrompt");
475
- }
476
- if (hasLLMRead) {
477
- normalized.push("LLMRead");
478
- }
479
- if (hasReadonly) {
480
- normalized.push("readonly");
481
- } else if (hasLLMWrite) {
482
- normalized.push("LLMWrite");
456
+ if (["SystemPrompt", "LLMRead", "LLMWrite", "protected", "ApplyTemplate"].includes(tag)) {
457
+ if (!seen.has(tag)) {
458
+ seen.add(tag);
459
+ normalized.push(tag);
460
+ }
461
+ }
483
462
  }
484
463
  return normalized;
485
464
  }
@@ -503,7 +482,7 @@ var MindCache = class {
503
482
  _historyOptions = { maxEntries: 100, snapshotInterval: 10 };
504
483
  _historyEnabled = false;
505
484
  constructor(options) {
506
- this.doc = new Y.Doc();
485
+ this.doc = options?.doc || new Y.Doc();
507
486
  this.rootMap = this.doc.getMap("mindcache");
508
487
  this.rootMap.observeDeep((events) => {
509
488
  const keysAffected = /* @__PURE__ */ new Set();
@@ -906,16 +885,10 @@ var MindCache = class {
906
885
  const attrs = entry.attributes || {};
907
886
  const normalizedAttrs = {
908
887
  type: attrs.type || "text",
888
+ contentType: attrs.contentType,
909
889
  contentTags: attrs.contentTags || [],
910
- systemTags: attrs.systemTags || this.normalizeSystemTags(attrs.visible !== false ? ["prompt"] : []),
911
- zIndex: attrs.zIndex ?? 0,
912
- // Legacy fields
913
- readonly: attrs.readonly ?? false,
914
- visible: attrs.visible ?? true,
915
- hardcoded: attrs.hardcoded ?? false,
916
- template: attrs.template ?? false,
917
- tags: attrs.tags || [],
918
- contentType: attrs.contentType
890
+ systemTags: this.normalizeSystemTags(attrs.systemTags || []),
891
+ zIndex: attrs.zIndex ?? 0
919
892
  };
920
893
  entryMap.set("attributes", normalizedAttrs);
921
894
  }
@@ -1020,7 +993,7 @@ var MindCache = class {
1020
993
  if (_processingStack && _processingStack.has(key)) {
1021
994
  return `{{${key}}}`;
1022
995
  }
1023
- if (attributes?.systemTags?.includes("ApplyTemplate") || attributes?.systemTags?.includes("template") || attributes?.template) {
996
+ if (attributes?.systemTags?.includes("ApplyTemplate")) {
1024
997
  if (typeof value === "string") {
1025
998
  const stack = _processingStack || /* @__PURE__ */ new Set();
1026
999
  stack.add(key);
@@ -1034,13 +1007,8 @@ var MindCache = class {
1034
1007
  return {
1035
1008
  type: "text",
1036
1009
  contentTags: [],
1037
- systemTags: ["prompt", "readonly", "protected"],
1038
- zIndex: 999999,
1039
- readonly: true,
1040
- visible: true,
1041
- hardcoded: true,
1042
- template: false,
1043
- tags: []
1010
+ systemTags: ["SystemPrompt", "protected"],
1011
+ zIndex: 999999
1044
1012
  };
1045
1013
  }
1046
1014
  const entryMap = this.rootMap.get(key);
@@ -1107,22 +1075,13 @@ var MindCache = class {
1107
1075
  this.getUndoManager(key);
1108
1076
  this.doc.transact(() => {
1109
1077
  const oldAttributes = isNewEntry ? {
1110
- ...DEFAULT_KEY_ATTRIBUTES,
1111
- contentTags: [],
1112
- systemTags: ["SystemPrompt", "LLMWrite"],
1113
- tags: [],
1114
- zIndex: 0
1078
+ ...DEFAULT_KEY_ATTRIBUTES
1115
1079
  } : entryMap.get("attributes");
1116
1080
  const finalAttributes = attributes ? { ...oldAttributes, ...attributes } : oldAttributes;
1117
1081
  let normalizedAttributes = { ...finalAttributes };
1118
1082
  if (finalAttributes.systemTags) {
1119
1083
  normalizedAttributes.systemTags = this.normalizeSystemTags(finalAttributes.systemTags);
1120
1084
  }
1121
- if (finalAttributes.template) {
1122
- if (!normalizedAttributes.systemTags.includes("template")) {
1123
- normalizedAttributes.systemTags.push("template");
1124
- }
1125
- }
1126
1085
  let valueToSet = value;
1127
1086
  if (normalizedAttributes.type === "document" && !(valueToSet instanceof Y.Text)) {
1128
1087
  valueToSet = new Y.Text(typeof value === "string" ? value : String(value ?? ""));
@@ -1133,6 +1092,38 @@ var MindCache = class {
1133
1092
  entryMap.set("attributes", normalizedAttributes);
1134
1093
  });
1135
1094
  }
1095
+ /**
1096
+ * LLM-safe method to write a value to a key.
1097
+ * This method:
1098
+ * - Only updates the value, never modifies attributes/systemTags
1099
+ * - Checks LLMWrite permission before writing
1100
+ * - Returns false if key doesn't exist or lacks LLMWrite permission
1101
+ *
1102
+ * Used by create_vercel_ai_tools() to prevent LLMs from escalating privileges.
1103
+ */
1104
+ llm_set_key(key, value) {
1105
+ if (key === "$date" || key === "$time" || key === "$version") {
1106
+ return false;
1107
+ }
1108
+ const entryMap = this.rootMap.get(key);
1109
+ if (!entryMap) {
1110
+ return false;
1111
+ }
1112
+ const attributes = entryMap.get("attributes");
1113
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
1114
+ return false;
1115
+ }
1116
+ if (attributes.type === "document") {
1117
+ if (typeof value === "string") {
1118
+ this._replaceDocumentText(key, value);
1119
+ }
1120
+ return true;
1121
+ }
1122
+ this.doc.transact(() => {
1123
+ entryMap.set("value", value);
1124
+ });
1125
+ return true;
1126
+ }
1136
1127
  delete_key(key) {
1137
1128
  if (key === "$date" || key === "$time") {
1138
1129
  return;
@@ -1577,15 +1568,13 @@ var MindCache = class {
1577
1568
  }
1578
1569
  const attributes = entryMap.get("attributes");
1579
1570
  const value = entryMap.get("value");
1580
- if (attributes?.hardcoded) {
1571
+ if (attributes?.systemTags?.includes("protected")) {
1581
1572
  return;
1582
1573
  }
1583
1574
  lines.push(`### ${key}`);
1584
1575
  const entryType = attributes?.type || "text";
1585
1576
  lines.push(`- **Type**: \`${entryType}\``);
1586
- lines.push(`- **Readonly**: \`${attributes?.readonly ?? false}\``);
1587
- lines.push(`- **Visible**: \`${attributes?.visible ?? true}\``);
1588
- lines.push(`- **Template**: \`${attributes?.template ?? false}\``);
1577
+ lines.push(`- **System Tags**: \`${attributes?.systemTags?.join(", ") || "none"}\``);
1589
1578
  lines.push(`- **Z-Index**: \`${attributes?.zIndex ?? 0}\``);
1590
1579
  if (attributes?.contentTags && attributes.contentTags.length > 0) {
1591
1580
  lines.push(`- **Tags**: \`${attributes.contentTags.join("`, `")}\``);
@@ -1615,7 +1604,10 @@ var MindCache = class {
1615
1604
  }
1616
1605
  lines.push("```");
1617
1606
  } else {
1618
- lines.push(`- **Value**: ${value}`);
1607
+ lines.push("- **Value**:");
1608
+ lines.push("```");
1609
+ lines.push(String(value));
1610
+ lines.push("```");
1619
1611
  }
1620
1612
  lines.push("");
1621
1613
  });
@@ -1650,7 +1642,7 @@ var MindCache = class {
1650
1642
  for (const line of lines) {
1651
1643
  if (line.startsWith("### ") && !line.startsWith("### Appendix")) {
1652
1644
  if (currentKey && currentValue !== null) {
1653
- this.set_value(currentKey, currentValue, currentAttributes);
1645
+ this.set_value(currentKey, currentValue.trim(), currentAttributes);
1654
1646
  }
1655
1647
  currentKey = line.substring(4).trim();
1656
1648
  currentAttributes = {};
@@ -1671,16 +1663,11 @@ var MindCache = class {
1671
1663
  }
1672
1664
  continue;
1673
1665
  }
1674
- if (line.startsWith("- **Readonly**:")) {
1675
- currentAttributes.readonly = line.includes("`true`");
1676
- continue;
1677
- }
1678
- if (line.startsWith("- **Visible**:")) {
1679
- currentAttributes.visible = line.includes("`true`");
1680
- continue;
1681
- }
1682
- if (line.startsWith("- **Template**:")) {
1683
- currentAttributes.template = line.includes("`true`");
1666
+ if (line.startsWith("- **System Tags**:")) {
1667
+ const tagsStr = line.match(/`([^`]+)`/)?.[1] || "";
1668
+ if (tagsStr !== "none") {
1669
+ currentAttributes.systemTags = tagsStr.split(", ").filter((t) => t);
1670
+ }
1684
1671
  continue;
1685
1672
  }
1686
1673
  if (line.startsWith("- **Z-Index**:")) {
@@ -1691,7 +1678,6 @@ var MindCache = class {
1691
1678
  if (line.startsWith("- **Tags**:")) {
1692
1679
  const tags = line.match(/`([^`]+)`/g)?.map((t) => t.slice(1, -1)) || [];
1693
1680
  currentAttributes.contentTags = tags;
1694
- currentAttributes.tags = tags;
1695
1681
  continue;
1696
1682
  }
1697
1683
  if (line.startsWith("- **Content Type**:")) {
@@ -1699,10 +1685,24 @@ var MindCache = class {
1699
1685
  continue;
1700
1686
  }
1701
1687
  if (line.startsWith("- **Value**:") && !line.includes("[See Appendix")) {
1702
- currentValue = line.substring(12).trim();
1688
+ const afterValue = line.substring(12).trim();
1689
+ if (afterValue === "") {
1690
+ currentValue = "";
1691
+ } else if (afterValue === "```" || afterValue === "```json") {
1692
+ inCodeBlock = true;
1693
+ codeBlockContent = [];
1694
+ currentValue = "";
1695
+ } else if (afterValue.startsWith("```")) {
1696
+ inCodeBlock = true;
1697
+ codeBlockContent = [afterValue.substring(3)];
1698
+ currentValue = "";
1699
+ } else {
1700
+ currentValue = afterValue;
1701
+ }
1703
1702
  continue;
1704
1703
  }
1705
- if (line === "```json" || line === "```") {
1704
+ const trimmedLine = line.trim();
1705
+ if (trimmedLine === "```json" || trimmedLine === "```") {
1706
1706
  if (inCodeBlock) {
1707
1707
  inCodeBlock = false;
1708
1708
  if (currentKey && codeBlockContent.length > 0) {
@@ -1711,15 +1711,27 @@ var MindCache = class {
1711
1711
  codeBlockContent = [];
1712
1712
  } else {
1713
1713
  inCodeBlock = true;
1714
+ codeBlockContent = [];
1714
1715
  }
1715
1716
  continue;
1716
1717
  }
1717
1718
  if (inCodeBlock) {
1718
1719
  codeBlockContent.push(line);
1720
+ } else if (currentKey && currentValue !== null) {
1721
+ currentValue += "\n" + line;
1719
1722
  }
1720
1723
  }
1721
1724
  if (currentKey && currentValue !== null) {
1722
- this.set_value(currentKey, currentValue, currentAttributes);
1725
+ this.set_value(currentKey, currentValue.trim(), currentAttributes);
1726
+ }
1727
+ const hasParsedKeys = lines.some((line) => line.startsWith("### ") && !line.startsWith("### Appendix"));
1728
+ if (!hasParsedKeys && markdown.trim().length > 0) {
1729
+ this.set_value("imported_content", markdown.trim(), {
1730
+ type: "text",
1731
+ systemTags: ["SystemPrompt", "LLMWrite"],
1732
+ // Default assumptions
1733
+ zIndex: 0
1734
+ });
1723
1735
  }
1724
1736
  }
1725
1737
  /**
@@ -1947,8 +1959,12 @@ var MindCache = class {
1947
1959
  /**
1948
1960
  * Generate Vercel AI SDK compatible tools for writable keys.
1949
1961
  * For document type keys, generates additional tools: append_, insert_, edit_
1962
+ *
1963
+ * Security: All tools use llm_set_key internally which:
1964
+ * - Only modifies VALUES, never attributes/systemTags
1965
+ * - Prevents LLMs from escalating privileges
1950
1966
  */
1951
- get_aisdk_tools() {
1967
+ create_vercel_ai_tools() {
1952
1968
  const tools = {};
1953
1969
  for (const [key, val] of this.rootMap) {
1954
1970
  if (key.startsWith("$")) {
@@ -1956,7 +1972,7 @@ var MindCache = class {
1956
1972
  }
1957
1973
  const entryMap = val;
1958
1974
  const attributes = entryMap.get("attributes");
1959
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
1975
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
1960
1976
  if (!isWritable) {
1961
1977
  continue;
1962
1978
  }
@@ -1972,15 +1988,18 @@ var MindCache = class {
1972
1988
  required: ["value"]
1973
1989
  },
1974
1990
  execute: async ({ value }) => {
1975
- if (isDocument) {
1976
- this._replaceDocumentText(key, value);
1977
- } else {
1978
- this.set_value(key, value);
1991
+ const success = this.llm_set_key(key, value);
1992
+ if (success) {
1993
+ return {
1994
+ result: `Successfully wrote "${value}" to ${key}`,
1995
+ key,
1996
+ value
1997
+ };
1979
1998
  }
1980
1999
  return {
1981
- result: `Successfully wrote "${value}" to ${key}`,
2000
+ result: `Failed to write to ${key} - permission denied or key not found`,
1982
2001
  key,
1983
- value
2002
+ error: true
1984
2003
  };
1985
2004
  }
1986
2005
  };
@@ -1995,6 +2014,9 @@ var MindCache = class {
1995
2014
  required: ["text"]
1996
2015
  },
1997
2016
  execute: async ({ text }) => {
2017
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
2018
+ return { result: `Permission denied for ${key}`, key, error: true };
2019
+ }
1998
2020
  const yText = this.get_document(key);
1999
2021
  if (yText) {
2000
2022
  yText.insert(yText.length, text);
@@ -2018,6 +2040,9 @@ var MindCache = class {
2018
2040
  required: ["index", "text"]
2019
2041
  },
2020
2042
  execute: async ({ index, text }) => {
2043
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
2044
+ return { result: `Permission denied for ${key}`, key, error: true };
2045
+ }
2021
2046
  this.insert_text(key, index, text);
2022
2047
  return {
2023
2048
  result: `Successfully inserted text at position ${index} in ${key}`,
@@ -2038,6 +2063,9 @@ var MindCache = class {
2038
2063
  required: ["find", "replace"]
2039
2064
  },
2040
2065
  execute: async ({ find, replace }) => {
2066
+ if (!attributes?.systemTags?.includes("LLMWrite")) {
2067
+ return { result: `Permission denied for ${key}`, key, error: true };
2068
+ }
2041
2069
  const yText = this.get_document(key);
2042
2070
  if (yText) {
2043
2071
  const text = yText.toString();
@@ -2062,6 +2090,12 @@ var MindCache = class {
2062
2090
  }
2063
2091
  return tools;
2064
2092
  }
2093
+ /**
2094
+ * @deprecated Use create_vercel_ai_tools() instead
2095
+ */
2096
+ get_aisdk_tools() {
2097
+ return this.create_vercel_ai_tools();
2098
+ }
2065
2099
  /**
2066
2100
  * Generate a system prompt containing all visible STM keys and their values.
2067
2101
  * Indicates which tools can be used to modify writable keys.
@@ -2074,13 +2108,13 @@ var MindCache = class {
2074
2108
  }
2075
2109
  const entryMap = val;
2076
2110
  const attributes = entryMap.get("attributes");
2077
- const isVisible = attributes?.visible !== false && (attributes?.systemTags?.includes("prompt") || attributes?.systemTags?.includes("SystemPrompt") || !attributes?.systemTags);
2111
+ const isVisible = attributes?.systemTags?.includes("SystemPrompt") || attributes?.systemTags?.includes("LLMRead");
2078
2112
  if (!isVisible) {
2079
2113
  continue;
2080
2114
  }
2081
2115
  const value = this.get_value(key);
2082
2116
  const displayValue = typeof value === "object" ? JSON.stringify(value) : value;
2083
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
2117
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
2084
2118
  const isDocument = attributes?.type === "document";
2085
2119
  const sanitizedKey = this.sanitizeKeyForTool(key);
2086
2120
  if (isWritable) {
@@ -2121,7 +2155,7 @@ var MindCache = class {
2121
2155
  return null;
2122
2156
  }
2123
2157
  const attributes = entryMap.get("attributes");
2124
- const isWritable = !attributes?.readonly && (attributes?.systemTags?.includes("LLMWrite") || !attributes?.systemTags);
2158
+ const isWritable = attributes?.systemTags?.includes("LLMWrite");
2125
2159
  if (!isWritable) {
2126
2160
  return null;
2127
2161
  }