mindcache 3.1.0 → 3.3.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/{CloudAdapter-Bx-ITNdi.d.mts → CloudAdapter-CSncOr3V.d.mts} +168 -4
- package/dist/{CloudAdapter-Bx-ITNdi.d.ts → CloudAdapter-CSncOr3V.d.ts} +168 -4
- package/dist/cloud/index.d.mts +2 -2
- package/dist/cloud/index.d.ts +2 -2
- package/dist/cloud/index.js +722 -16
- package/dist/cloud/index.js.map +1 -1
- package/dist/cloud/index.mjs +722 -16
- package/dist/cloud/index.mjs.map +1 -1
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +726 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +726 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cloud/index.js
CHANGED
|
@@ -353,6 +353,8 @@ var init_CloudAdapter = __esm({
|
|
|
353
353
|
} else if (msg.type === "auth_error" || msg.type === "error") {
|
|
354
354
|
this._state = "error";
|
|
355
355
|
this.emit("error", new Error(msg.error));
|
|
356
|
+
} else {
|
|
357
|
+
console.debug("MindCache Cloud: Received message type:", msg.type, msg);
|
|
356
358
|
}
|
|
357
359
|
} else {
|
|
358
360
|
const encoder = encoding__namespace.createEncoder();
|
|
@@ -461,8 +463,6 @@ var MindCache = class {
|
|
|
461
463
|
normalized.push("readonly");
|
|
462
464
|
} else if (hasLLMWrite) {
|
|
463
465
|
normalized.push("LLMWrite");
|
|
464
|
-
} else {
|
|
465
|
-
normalized.push("LLMWrite");
|
|
466
466
|
}
|
|
467
467
|
return normalized;
|
|
468
468
|
}
|
|
@@ -685,14 +685,16 @@ var MindCache = class {
|
|
|
685
685
|
}
|
|
686
686
|
const CloudAdapter2 = await this._getCloudAdapterClass();
|
|
687
687
|
if (!this._cloudConfig.baseUrl) ;
|
|
688
|
-
const baseUrl = (this._cloudConfig.baseUrl || "https://api.mindcache.
|
|
688
|
+
const baseUrl = (this._cloudConfig.baseUrl || "https://api.mindcache.dev").replace("https://", "wss://").replace("http://", "ws://");
|
|
689
689
|
const adapter = new CloudAdapter2({
|
|
690
690
|
instanceId: this._cloudConfig.instanceId,
|
|
691
691
|
projectId: this._cloudConfig.projectId || "default",
|
|
692
692
|
baseUrl,
|
|
693
693
|
apiKey: this._cloudConfig.apiKey
|
|
694
694
|
});
|
|
695
|
-
if (this._cloudConfig.
|
|
695
|
+
if (this._cloudConfig.tokenProvider) {
|
|
696
|
+
adapter.setTokenProvider(this._cloudConfig.tokenProvider);
|
|
697
|
+
} else if (this._cloudConfig.tokenEndpoint) {
|
|
696
698
|
const tokenEndpoint = this._cloudConfig.tokenEndpoint;
|
|
697
699
|
const instanceId = this._cloudConfig.instanceId;
|
|
698
700
|
let resolvedBaseUrl;
|
|
@@ -826,18 +828,35 @@ var MindCache = class {
|
|
|
826
828
|
}
|
|
827
829
|
// Deserialize state (for IndexedDBAdapter compatibility)
|
|
828
830
|
deserialize(data) {
|
|
831
|
+
if (!data || typeof data !== "object") {
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
829
834
|
this.doc.transact(() => {
|
|
835
|
+
for (const key of this.rootMap.keys()) {
|
|
836
|
+
this.rootMap.delete(key);
|
|
837
|
+
}
|
|
830
838
|
for (const [key, entry] of Object.entries(data)) {
|
|
831
839
|
if (key.startsWith("$")) {
|
|
832
840
|
continue;
|
|
833
841
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
entryMap = new Y__namespace.Map();
|
|
837
|
-
this.rootMap.set(key, entryMap);
|
|
838
|
-
}
|
|
842
|
+
const entryMap = new Y__namespace.Map();
|
|
843
|
+
this.rootMap.set(key, entryMap);
|
|
839
844
|
entryMap.set("value", entry.value);
|
|
840
|
-
|
|
845
|
+
const attrs = entry.attributes || {};
|
|
846
|
+
const normalizedAttrs = {
|
|
847
|
+
type: attrs.type || "text",
|
|
848
|
+
contentTags: attrs.contentTags || [],
|
|
849
|
+
systemTags: attrs.systemTags || this.normalizeSystemTags(attrs.visible !== false ? ["prompt"] : []),
|
|
850
|
+
zIndex: attrs.zIndex ?? 0,
|
|
851
|
+
// Legacy fields
|
|
852
|
+
readonly: attrs.readonly ?? false,
|
|
853
|
+
visible: attrs.visible ?? true,
|
|
854
|
+
hardcoded: attrs.hardcoded ?? false,
|
|
855
|
+
template: attrs.template ?? false,
|
|
856
|
+
tags: attrs.tags || [],
|
|
857
|
+
contentType: attrs.contentType
|
|
858
|
+
};
|
|
859
|
+
entryMap.set("attributes", normalizedAttrs);
|
|
841
860
|
}
|
|
842
861
|
});
|
|
843
862
|
}
|
|
@@ -875,16 +894,46 @@ var MindCache = class {
|
|
|
875
894
|
}
|
|
876
895
|
return false;
|
|
877
896
|
}
|
|
878
|
-
// InjectSTM replacement
|
|
879
|
-
|
|
897
|
+
// InjectSTM replacement (private helper)
|
|
898
|
+
_injectSTMInternal(template, _processingStack) {
|
|
880
899
|
return template.replace(/\{\{([^}]+)\}\}/g, (_, key) => {
|
|
881
900
|
const val = this.get_value(key.trim(), _processingStack);
|
|
882
901
|
return val !== void 0 ? String(val) : `{{${key}}}`;
|
|
883
902
|
});
|
|
884
903
|
}
|
|
904
|
+
/**
|
|
905
|
+
* Replace {{key}} placeholders in a template string with values from MindCache.
|
|
906
|
+
* @param template The template string with {{key}} placeholders
|
|
907
|
+
* @returns The template with placeholders replaced by values
|
|
908
|
+
*/
|
|
909
|
+
injectSTM(template) {
|
|
910
|
+
return this._injectSTMInternal(template, /* @__PURE__ */ new Set());
|
|
911
|
+
}
|
|
885
912
|
// Public API Methods
|
|
886
913
|
getAll() {
|
|
887
|
-
|
|
914
|
+
const result = {};
|
|
915
|
+
for (const [key] of this.rootMap) {
|
|
916
|
+
result[key] = this.get_value(key);
|
|
917
|
+
}
|
|
918
|
+
result["$date"] = this.get_value("$date");
|
|
919
|
+
result["$time"] = this.get_value("$time");
|
|
920
|
+
return result;
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Get all entries with their full structure (value + attributes).
|
|
924
|
+
* Use this for UI/admin interfaces that need to display key properties.
|
|
925
|
+
* Unlike serialize(), this format is stable and won't change.
|
|
926
|
+
*/
|
|
927
|
+
getAllEntries() {
|
|
928
|
+
const result = {};
|
|
929
|
+
for (const [key] of this.rootMap) {
|
|
930
|
+
const value = this.get_value(key);
|
|
931
|
+
const attributes = this.get_attributes(key);
|
|
932
|
+
if (attributes) {
|
|
933
|
+
result[key] = { value, attributes };
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
return result;
|
|
888
937
|
}
|
|
889
938
|
get_value(key, _processingStack) {
|
|
890
939
|
if (key === "$date") {
|
|
@@ -914,7 +963,7 @@ var MindCache = class {
|
|
|
914
963
|
if (typeof value === "string") {
|
|
915
964
|
const stack = _processingStack || /* @__PURE__ */ new Set();
|
|
916
965
|
stack.add(key);
|
|
917
|
-
return this.
|
|
966
|
+
return this._injectSTMInternal(value, stack);
|
|
918
967
|
}
|
|
919
968
|
}
|
|
920
969
|
return value;
|
|
@@ -936,6 +985,27 @@ var MindCache = class {
|
|
|
936
985
|
const entryMap = this.rootMap.get(key);
|
|
937
986
|
return entryMap ? entryMap.get("attributes") : void 0;
|
|
938
987
|
}
|
|
988
|
+
/**
|
|
989
|
+
* Update only the attributes of a key without modifying the value.
|
|
990
|
+
* Useful for updating tags, permissions etc. on document type keys.
|
|
991
|
+
*/
|
|
992
|
+
set_attributes(key, attributes) {
|
|
993
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
994
|
+
return;
|
|
995
|
+
}
|
|
996
|
+
const entryMap = this.rootMap.get(key);
|
|
997
|
+
if (!entryMap) {
|
|
998
|
+
return;
|
|
999
|
+
}
|
|
1000
|
+
this.doc.transact(() => {
|
|
1001
|
+
const existingAttrs = entryMap.get("attributes");
|
|
1002
|
+
const mergedAttrs = { ...existingAttrs, ...attributes };
|
|
1003
|
+
if (mergedAttrs.systemTags) {
|
|
1004
|
+
mergedAttrs.systemTags = this.normalizeSystemTags(mergedAttrs.systemTags);
|
|
1005
|
+
}
|
|
1006
|
+
entryMap.set("attributes", mergedAttrs);
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
939
1009
|
set_value(key, value, attributes) {
|
|
940
1010
|
if (key === "$date" || key === "$time" || key === "$version") {
|
|
941
1011
|
return;
|
|
@@ -991,6 +1061,638 @@ var MindCache = class {
|
|
|
991
1061
|
keys.forEach((k) => this.rootMap.delete(k));
|
|
992
1062
|
});
|
|
993
1063
|
}
|
|
1064
|
+
// ============================================
|
|
1065
|
+
// Restored Methods (from v2.x)
|
|
1066
|
+
// ============================================
|
|
1067
|
+
/**
|
|
1068
|
+
* Check if a key exists in MindCache.
|
|
1069
|
+
*/
|
|
1070
|
+
has(key) {
|
|
1071
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1072
|
+
return true;
|
|
1073
|
+
}
|
|
1074
|
+
return this.rootMap.has(key);
|
|
1075
|
+
}
|
|
1076
|
+
/**
|
|
1077
|
+
* Delete a key from MindCache.
|
|
1078
|
+
* @returns true if the key existed and was deleted
|
|
1079
|
+
*/
|
|
1080
|
+
delete(key) {
|
|
1081
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1082
|
+
return false;
|
|
1083
|
+
}
|
|
1084
|
+
if (!this.rootMap.has(key)) {
|
|
1085
|
+
return false;
|
|
1086
|
+
}
|
|
1087
|
+
this.rootMap.delete(key);
|
|
1088
|
+
this.notifyGlobalListeners();
|
|
1089
|
+
if (this.listeners[key]) {
|
|
1090
|
+
this.listeners[key].forEach((listener) => listener(void 0));
|
|
1091
|
+
}
|
|
1092
|
+
return true;
|
|
1093
|
+
}
|
|
1094
|
+
/** @deprecated Use get_value instead */
|
|
1095
|
+
get(key) {
|
|
1096
|
+
return this.get_value(key);
|
|
1097
|
+
}
|
|
1098
|
+
/** @deprecated Use set_value instead */
|
|
1099
|
+
set(key, value) {
|
|
1100
|
+
this.set_value(key, value);
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Update multiple values at once from an object.
|
|
1104
|
+
* @deprecated Use set_value for individual keys
|
|
1105
|
+
*/
|
|
1106
|
+
update(data) {
|
|
1107
|
+
this.doc.transact(() => {
|
|
1108
|
+
for (const [key, value] of Object.entries(data)) {
|
|
1109
|
+
if (key !== "$date" && key !== "$time" && key !== "$version") {
|
|
1110
|
+
this.set_value(key, value);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
this.notifyGlobalListeners();
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Get the number of keys in MindCache.
|
|
1118
|
+
*/
|
|
1119
|
+
size() {
|
|
1120
|
+
return this.rootMap.size + 2;
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Get all keys in MindCache (including temporal keys).
|
|
1124
|
+
*/
|
|
1125
|
+
keys() {
|
|
1126
|
+
const keys = Array.from(this.rootMap.keys());
|
|
1127
|
+
keys.push("$date", "$time");
|
|
1128
|
+
return keys;
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Get all values in MindCache (including temporal values).
|
|
1132
|
+
*/
|
|
1133
|
+
values() {
|
|
1134
|
+
const result = [];
|
|
1135
|
+
for (const [key] of this.rootMap) {
|
|
1136
|
+
result.push(this.get_value(key));
|
|
1137
|
+
}
|
|
1138
|
+
result.push(this.get_value("$date"));
|
|
1139
|
+
result.push(this.get_value("$time"));
|
|
1140
|
+
return result;
|
|
1141
|
+
}
|
|
1142
|
+
/**
|
|
1143
|
+
* Get all key-value entries (including temporal entries).
|
|
1144
|
+
*/
|
|
1145
|
+
entries() {
|
|
1146
|
+
const result = [];
|
|
1147
|
+
for (const [key] of this.rootMap) {
|
|
1148
|
+
result.push([key, this.get_value(key)]);
|
|
1149
|
+
}
|
|
1150
|
+
result.push(["$date", this.get_value("$date")]);
|
|
1151
|
+
result.push(["$time", this.get_value("$time")]);
|
|
1152
|
+
return result;
|
|
1153
|
+
}
|
|
1154
|
+
/**
|
|
1155
|
+
* Unsubscribe from key changes.
|
|
1156
|
+
* @deprecated Use the cleanup function returned by subscribe() instead
|
|
1157
|
+
*/
|
|
1158
|
+
unsubscribe(key, listener) {
|
|
1159
|
+
if (this.listeners[key]) {
|
|
1160
|
+
this.listeners[key] = this.listeners[key].filter((l) => l !== listener);
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* Get the STM as a formatted string for LLM context.
|
|
1165
|
+
* @deprecated Use get_system_prompt() instead
|
|
1166
|
+
*/
|
|
1167
|
+
getSTM() {
|
|
1168
|
+
return this.get_system_prompt();
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Get the STM as an object with values directly (no attributes).
|
|
1172
|
+
* Includes system keys ($date, $time).
|
|
1173
|
+
* @deprecated Use getAll() for full STM format
|
|
1174
|
+
*/
|
|
1175
|
+
getSTMObject() {
|
|
1176
|
+
const result = {};
|
|
1177
|
+
for (const [key] of this.rootMap) {
|
|
1178
|
+
result[key] = this.get_value(key);
|
|
1179
|
+
}
|
|
1180
|
+
result["$date"] = this.get_value("$date");
|
|
1181
|
+
result["$time"] = this.get_value("$time");
|
|
1182
|
+
return result;
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Add a content tag to a key.
|
|
1186
|
+
* @returns true if the tag was added, false if key doesn't exist or tag already exists
|
|
1187
|
+
*/
|
|
1188
|
+
addTag(key, tag) {
|
|
1189
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1190
|
+
return false;
|
|
1191
|
+
}
|
|
1192
|
+
const entryMap = this.rootMap.get(key);
|
|
1193
|
+
if (!entryMap) {
|
|
1194
|
+
return false;
|
|
1195
|
+
}
|
|
1196
|
+
const attributes = entryMap.get("attributes");
|
|
1197
|
+
const contentTags = attributes?.contentTags || [];
|
|
1198
|
+
if (contentTags.includes(tag)) {
|
|
1199
|
+
return false;
|
|
1200
|
+
}
|
|
1201
|
+
this.doc.transact(() => {
|
|
1202
|
+
const newContentTags = [...contentTags, tag];
|
|
1203
|
+
entryMap.set("attributes", {
|
|
1204
|
+
...attributes,
|
|
1205
|
+
contentTags: newContentTags,
|
|
1206
|
+
tags: newContentTags
|
|
1207
|
+
// Sync legacy tags array
|
|
1208
|
+
});
|
|
1209
|
+
});
|
|
1210
|
+
this.notifyGlobalListeners();
|
|
1211
|
+
return true;
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Remove a content tag from a key.
|
|
1215
|
+
* @returns true if the tag was removed
|
|
1216
|
+
*/
|
|
1217
|
+
removeTag(key, tag) {
|
|
1218
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1219
|
+
return false;
|
|
1220
|
+
}
|
|
1221
|
+
const entryMap = this.rootMap.get(key);
|
|
1222
|
+
if (!entryMap) {
|
|
1223
|
+
return false;
|
|
1224
|
+
}
|
|
1225
|
+
const attributes = entryMap.get("attributes");
|
|
1226
|
+
const contentTags = attributes?.contentTags || [];
|
|
1227
|
+
const tagIndex = contentTags.indexOf(tag);
|
|
1228
|
+
if (tagIndex === -1) {
|
|
1229
|
+
return false;
|
|
1230
|
+
}
|
|
1231
|
+
this.doc.transact(() => {
|
|
1232
|
+
const newContentTags = contentTags.filter((t) => t !== tag);
|
|
1233
|
+
entryMap.set("attributes", {
|
|
1234
|
+
...attributes,
|
|
1235
|
+
contentTags: newContentTags,
|
|
1236
|
+
tags: newContentTags
|
|
1237
|
+
// Sync legacy tags array
|
|
1238
|
+
});
|
|
1239
|
+
});
|
|
1240
|
+
this.notifyGlobalListeners();
|
|
1241
|
+
return true;
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Get all content tags for a key.
|
|
1245
|
+
*/
|
|
1246
|
+
getTags(key) {
|
|
1247
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1248
|
+
return [];
|
|
1249
|
+
}
|
|
1250
|
+
const entryMap = this.rootMap.get(key);
|
|
1251
|
+
if (!entryMap) {
|
|
1252
|
+
return [];
|
|
1253
|
+
}
|
|
1254
|
+
const attributes = entryMap.get("attributes");
|
|
1255
|
+
return attributes?.contentTags || [];
|
|
1256
|
+
}
|
|
1257
|
+
/**
|
|
1258
|
+
* Get all unique content tags across all keys.
|
|
1259
|
+
*/
|
|
1260
|
+
getAllTags() {
|
|
1261
|
+
const allTags = /* @__PURE__ */ new Set();
|
|
1262
|
+
for (const [, val] of this.rootMap) {
|
|
1263
|
+
const entryMap = val;
|
|
1264
|
+
const attributes = entryMap.get("attributes");
|
|
1265
|
+
if (attributes?.contentTags) {
|
|
1266
|
+
attributes.contentTags.forEach((tag) => allTags.add(tag));
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
return Array.from(allTags);
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Check if a key has a specific content tag.
|
|
1273
|
+
*/
|
|
1274
|
+
hasTag(key, tag) {
|
|
1275
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1276
|
+
return false;
|
|
1277
|
+
}
|
|
1278
|
+
const entryMap = this.rootMap.get(key);
|
|
1279
|
+
if (!entryMap) {
|
|
1280
|
+
return false;
|
|
1281
|
+
}
|
|
1282
|
+
const attributes = entryMap.get("attributes");
|
|
1283
|
+
return attributes?.contentTags?.includes(tag) || false;
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
* Get all keys with a specific content tag as formatted string.
|
|
1287
|
+
*/
|
|
1288
|
+
getTagged(tag) {
|
|
1289
|
+
const entries = [];
|
|
1290
|
+
const keys = this.getSortedKeys();
|
|
1291
|
+
keys.forEach((key) => {
|
|
1292
|
+
if (this.hasTag(key, tag)) {
|
|
1293
|
+
entries.push([key, this.get_value(key)]);
|
|
1294
|
+
}
|
|
1295
|
+
});
|
|
1296
|
+
return entries.map(([key, value]) => `${key}: ${value}`).join(", ");
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Get array of keys with a specific content tag.
|
|
1300
|
+
*/
|
|
1301
|
+
getKeysByTag(tag) {
|
|
1302
|
+
const keys = this.getSortedKeys();
|
|
1303
|
+
return keys.filter((key) => this.hasTag(key, tag));
|
|
1304
|
+
}
|
|
1305
|
+
// ============================================
|
|
1306
|
+
// System Tag Methods (requires system access level)
|
|
1307
|
+
// ============================================
|
|
1308
|
+
/**
|
|
1309
|
+
* Add a system tag to a key (requires system access).
|
|
1310
|
+
* System tags: 'SystemPrompt', 'LLMRead', 'LLMWrite', 'readonly', 'protected', 'ApplyTemplate'
|
|
1311
|
+
*/
|
|
1312
|
+
systemAddTag(key, tag) {
|
|
1313
|
+
if (!this.hasSystemAccess) {
|
|
1314
|
+
console.warn("MindCache: systemAddTag requires system access level");
|
|
1315
|
+
return false;
|
|
1316
|
+
}
|
|
1317
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1318
|
+
return false;
|
|
1319
|
+
}
|
|
1320
|
+
const entryMap = this.rootMap.get(key);
|
|
1321
|
+
if (!entryMap) {
|
|
1322
|
+
return false;
|
|
1323
|
+
}
|
|
1324
|
+
const attributes = entryMap.get("attributes");
|
|
1325
|
+
const systemTags = attributes?.systemTags || [];
|
|
1326
|
+
if (systemTags.includes(tag)) {
|
|
1327
|
+
return false;
|
|
1328
|
+
}
|
|
1329
|
+
this.doc.transact(() => {
|
|
1330
|
+
const newSystemTags = [...systemTags, tag];
|
|
1331
|
+
const normalizedTags = this.normalizeSystemTags(newSystemTags);
|
|
1332
|
+
entryMap.set("attributes", {
|
|
1333
|
+
...attributes,
|
|
1334
|
+
systemTags: normalizedTags
|
|
1335
|
+
});
|
|
1336
|
+
});
|
|
1337
|
+
this.notifyGlobalListeners();
|
|
1338
|
+
return true;
|
|
1339
|
+
}
|
|
1340
|
+
/**
|
|
1341
|
+
* Remove a system tag from a key (requires system access).
|
|
1342
|
+
*/
|
|
1343
|
+
systemRemoveTag(key, tag) {
|
|
1344
|
+
if (!this.hasSystemAccess) {
|
|
1345
|
+
console.warn("MindCache: systemRemoveTag requires system access level");
|
|
1346
|
+
return false;
|
|
1347
|
+
}
|
|
1348
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1349
|
+
return false;
|
|
1350
|
+
}
|
|
1351
|
+
const entryMap = this.rootMap.get(key);
|
|
1352
|
+
if (!entryMap) {
|
|
1353
|
+
return false;
|
|
1354
|
+
}
|
|
1355
|
+
const attributes = entryMap.get("attributes");
|
|
1356
|
+
const systemTags = attributes?.systemTags || [];
|
|
1357
|
+
const tagIndex = systemTags.indexOf(tag);
|
|
1358
|
+
if (tagIndex === -1) {
|
|
1359
|
+
return false;
|
|
1360
|
+
}
|
|
1361
|
+
this.doc.transact(() => {
|
|
1362
|
+
const newSystemTags = systemTags.filter((t) => t !== tag);
|
|
1363
|
+
entryMap.set("attributes", {
|
|
1364
|
+
...attributes,
|
|
1365
|
+
systemTags: newSystemTags
|
|
1366
|
+
});
|
|
1367
|
+
});
|
|
1368
|
+
this.notifyGlobalListeners();
|
|
1369
|
+
return true;
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Get all system tags for a key (requires system access).
|
|
1373
|
+
*/
|
|
1374
|
+
systemGetTags(key) {
|
|
1375
|
+
if (!this.hasSystemAccess) {
|
|
1376
|
+
console.warn("MindCache: systemGetTags requires system access level");
|
|
1377
|
+
return [];
|
|
1378
|
+
}
|
|
1379
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1380
|
+
return [];
|
|
1381
|
+
}
|
|
1382
|
+
const entryMap = this.rootMap.get(key);
|
|
1383
|
+
if (!entryMap) {
|
|
1384
|
+
return [];
|
|
1385
|
+
}
|
|
1386
|
+
const attributes = entryMap.get("attributes");
|
|
1387
|
+
return attributes?.systemTags || [];
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Check if a key has a specific system tag (requires system access).
|
|
1391
|
+
*/
|
|
1392
|
+
systemHasTag(key, tag) {
|
|
1393
|
+
if (!this.hasSystemAccess) {
|
|
1394
|
+
console.warn("MindCache: systemHasTag requires system access level");
|
|
1395
|
+
return false;
|
|
1396
|
+
}
|
|
1397
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1398
|
+
return false;
|
|
1399
|
+
}
|
|
1400
|
+
const entryMap = this.rootMap.get(key);
|
|
1401
|
+
if (!entryMap) {
|
|
1402
|
+
return false;
|
|
1403
|
+
}
|
|
1404
|
+
const attributes = entryMap.get("attributes");
|
|
1405
|
+
return attributes?.systemTags?.includes(tag) || false;
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1408
|
+
* Set all system tags for a key at once (requires system access).
|
|
1409
|
+
*/
|
|
1410
|
+
systemSetTags(key, tags) {
|
|
1411
|
+
if (!this.hasSystemAccess) {
|
|
1412
|
+
console.warn("MindCache: systemSetTags requires system access level");
|
|
1413
|
+
return false;
|
|
1414
|
+
}
|
|
1415
|
+
if (key === "$date" || key === "$time" || key === "$version") {
|
|
1416
|
+
return false;
|
|
1417
|
+
}
|
|
1418
|
+
const entryMap = this.rootMap.get(key);
|
|
1419
|
+
if (!entryMap) {
|
|
1420
|
+
return false;
|
|
1421
|
+
}
|
|
1422
|
+
this.doc.transact(() => {
|
|
1423
|
+
const attributes = entryMap.get("attributes");
|
|
1424
|
+
entryMap.set("attributes", {
|
|
1425
|
+
...attributes,
|
|
1426
|
+
systemTags: [...tags]
|
|
1427
|
+
});
|
|
1428
|
+
});
|
|
1429
|
+
this.notifyGlobalListeners();
|
|
1430
|
+
return true;
|
|
1431
|
+
}
|
|
1432
|
+
/**
|
|
1433
|
+
* Get all keys with a specific system tag (requires system access).
|
|
1434
|
+
*/
|
|
1435
|
+
systemGetKeysByTag(tag) {
|
|
1436
|
+
if (!this.hasSystemAccess) {
|
|
1437
|
+
console.warn("MindCache: systemGetKeysByTag requires system access level");
|
|
1438
|
+
return [];
|
|
1439
|
+
}
|
|
1440
|
+
const keys = this.getSortedKeys();
|
|
1441
|
+
return keys.filter((key) => this.systemHasTag(key, tag));
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Helper to get sorted keys (by zIndex).
|
|
1445
|
+
*/
|
|
1446
|
+
getSortedKeys() {
|
|
1447
|
+
const entries = [];
|
|
1448
|
+
for (const [key, val] of this.rootMap) {
|
|
1449
|
+
const entryMap = val;
|
|
1450
|
+
const attributes = entryMap.get("attributes");
|
|
1451
|
+
entries.push({ key, zIndex: attributes?.zIndex ?? 0 });
|
|
1452
|
+
}
|
|
1453
|
+
return entries.sort((a, b) => a.zIndex - b.zIndex).map((e) => e.key);
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Serialize to JSON string.
|
|
1457
|
+
*/
|
|
1458
|
+
toJSON() {
|
|
1459
|
+
return JSON.stringify(this.serialize());
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Deserialize from JSON string.
|
|
1463
|
+
*/
|
|
1464
|
+
fromJSON(jsonString) {
|
|
1465
|
+
try {
|
|
1466
|
+
const data = JSON.parse(jsonString);
|
|
1467
|
+
this.deserialize(data);
|
|
1468
|
+
} catch (error) {
|
|
1469
|
+
console.error("MindCache: Failed to deserialize JSON:", error);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
/**
|
|
1473
|
+
* Export to Markdown format.
|
|
1474
|
+
*/
|
|
1475
|
+
toMarkdown() {
|
|
1476
|
+
const now = /* @__PURE__ */ new Date();
|
|
1477
|
+
const lines = [];
|
|
1478
|
+
const appendixEntries = [];
|
|
1479
|
+
let appendixCounter = 0;
|
|
1480
|
+
lines.push("# MindCache STM Export");
|
|
1481
|
+
lines.push("");
|
|
1482
|
+
lines.push(`Export Date: ${now.toISOString().split("T")[0]}`);
|
|
1483
|
+
lines.push("");
|
|
1484
|
+
lines.push("---");
|
|
1485
|
+
lines.push("");
|
|
1486
|
+
lines.push("## STM Entries");
|
|
1487
|
+
lines.push("");
|
|
1488
|
+
const sortedKeys = this.getSortedKeys();
|
|
1489
|
+
sortedKeys.forEach((key) => {
|
|
1490
|
+
const entryMap = this.rootMap.get(key);
|
|
1491
|
+
if (!entryMap) {
|
|
1492
|
+
return;
|
|
1493
|
+
}
|
|
1494
|
+
const attributes = entryMap.get("attributes");
|
|
1495
|
+
const value = entryMap.get("value");
|
|
1496
|
+
if (attributes?.hardcoded) {
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
lines.push(`### ${key}`);
|
|
1500
|
+
const entryType = attributes?.type || "text";
|
|
1501
|
+
lines.push(`- **Type**: \`${entryType}\``);
|
|
1502
|
+
lines.push(`- **Readonly**: \`${attributes?.readonly ?? false}\``);
|
|
1503
|
+
lines.push(`- **Visible**: \`${attributes?.visible ?? true}\``);
|
|
1504
|
+
lines.push(`- **Template**: \`${attributes?.template ?? false}\``);
|
|
1505
|
+
lines.push(`- **Z-Index**: \`${attributes?.zIndex ?? 0}\``);
|
|
1506
|
+
if (attributes?.contentTags && attributes.contentTags.length > 0) {
|
|
1507
|
+
lines.push(`- **Tags**: \`${attributes.contentTags.join("`, `")}\``);
|
|
1508
|
+
}
|
|
1509
|
+
if (attributes?.contentType) {
|
|
1510
|
+
lines.push(`- **Content Type**: \`${attributes.contentType}\``);
|
|
1511
|
+
}
|
|
1512
|
+
if (entryType === "image" || entryType === "file") {
|
|
1513
|
+
const label = String.fromCharCode(65 + appendixCounter);
|
|
1514
|
+
appendixCounter++;
|
|
1515
|
+
lines.push(`- **Value**: [See Appendix ${label}]`);
|
|
1516
|
+
appendixEntries.push({
|
|
1517
|
+
key,
|
|
1518
|
+
type: entryType,
|
|
1519
|
+
contentType: attributes?.contentType || "application/octet-stream",
|
|
1520
|
+
base64: value,
|
|
1521
|
+
label
|
|
1522
|
+
});
|
|
1523
|
+
} else if (entryType === "json") {
|
|
1524
|
+
lines.push("- **Value**:");
|
|
1525
|
+
lines.push("```json");
|
|
1526
|
+
try {
|
|
1527
|
+
const jsonValue = typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
1528
|
+
lines.push(jsonValue);
|
|
1529
|
+
} catch {
|
|
1530
|
+
lines.push(String(value));
|
|
1531
|
+
}
|
|
1532
|
+
lines.push("```");
|
|
1533
|
+
} else {
|
|
1534
|
+
lines.push(`- **Value**: ${value}`);
|
|
1535
|
+
}
|
|
1536
|
+
lines.push("");
|
|
1537
|
+
});
|
|
1538
|
+
if (appendixEntries.length > 0) {
|
|
1539
|
+
lines.push("---");
|
|
1540
|
+
lines.push("");
|
|
1541
|
+
lines.push("## Appendix: Binary Data");
|
|
1542
|
+
lines.push("");
|
|
1543
|
+
appendixEntries.forEach((entry) => {
|
|
1544
|
+
lines.push(`### Appendix ${entry.label}: ${entry.key}`);
|
|
1545
|
+
lines.push(`- **Type**: \`${entry.type}\``);
|
|
1546
|
+
lines.push(`- **Content Type**: \`${entry.contentType}\``);
|
|
1547
|
+
lines.push("- **Base64 Data**:");
|
|
1548
|
+
lines.push("```");
|
|
1549
|
+
lines.push(entry.base64);
|
|
1550
|
+
lines.push("```");
|
|
1551
|
+
lines.push("");
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1554
|
+
return lines.join("\n");
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Import from Markdown format.
|
|
1558
|
+
*/
|
|
1559
|
+
fromMarkdown(markdown) {
|
|
1560
|
+
const lines = markdown.split("\n");
|
|
1561
|
+
let currentKey = null;
|
|
1562
|
+
let currentAttributes = {};
|
|
1563
|
+
let currentValue = null;
|
|
1564
|
+
let inCodeBlock = false;
|
|
1565
|
+
let codeBlockContent = [];
|
|
1566
|
+
for (const line of lines) {
|
|
1567
|
+
if (line.startsWith("### ") && !line.startsWith("### Appendix")) {
|
|
1568
|
+
if (currentKey && currentValue !== null) {
|
|
1569
|
+
this.set_value(currentKey, currentValue, currentAttributes);
|
|
1570
|
+
}
|
|
1571
|
+
currentKey = line.substring(4).trim();
|
|
1572
|
+
currentAttributes = {};
|
|
1573
|
+
currentValue = null;
|
|
1574
|
+
continue;
|
|
1575
|
+
}
|
|
1576
|
+
if (line.startsWith("### Appendix ")) {
|
|
1577
|
+
const match = line.match(/### Appendix ([A-Z]): (.+)/);
|
|
1578
|
+
if (match) {
|
|
1579
|
+
currentKey = match[2];
|
|
1580
|
+
}
|
|
1581
|
+
continue;
|
|
1582
|
+
}
|
|
1583
|
+
if (line.startsWith("- **Type**:")) {
|
|
1584
|
+
const type = line.match(/`(.+)`/)?.[1];
|
|
1585
|
+
if (type) {
|
|
1586
|
+
currentAttributes.type = type;
|
|
1587
|
+
}
|
|
1588
|
+
continue;
|
|
1589
|
+
}
|
|
1590
|
+
if (line.startsWith("- **Readonly**:")) {
|
|
1591
|
+
currentAttributes.readonly = line.includes("`true`");
|
|
1592
|
+
continue;
|
|
1593
|
+
}
|
|
1594
|
+
if (line.startsWith("- **Visible**:")) {
|
|
1595
|
+
currentAttributes.visible = line.includes("`true`");
|
|
1596
|
+
continue;
|
|
1597
|
+
}
|
|
1598
|
+
if (line.startsWith("- **Template**:")) {
|
|
1599
|
+
currentAttributes.template = line.includes("`true`");
|
|
1600
|
+
continue;
|
|
1601
|
+
}
|
|
1602
|
+
if (line.startsWith("- **Z-Index**:")) {
|
|
1603
|
+
const zIndex = parseInt(line.match(/`(\d+)`/)?.[1] || "0", 10);
|
|
1604
|
+
currentAttributes.zIndex = zIndex;
|
|
1605
|
+
continue;
|
|
1606
|
+
}
|
|
1607
|
+
if (line.startsWith("- **Tags**:")) {
|
|
1608
|
+
const tags = line.match(/`([^`]+)`/g)?.map((t) => t.slice(1, -1)) || [];
|
|
1609
|
+
currentAttributes.contentTags = tags;
|
|
1610
|
+
currentAttributes.tags = tags;
|
|
1611
|
+
continue;
|
|
1612
|
+
}
|
|
1613
|
+
if (line.startsWith("- **Content Type**:")) {
|
|
1614
|
+
currentAttributes.contentType = line.match(/`(.+)`/)?.[1];
|
|
1615
|
+
continue;
|
|
1616
|
+
}
|
|
1617
|
+
if (line.startsWith("- **Value**:") && !line.includes("[See Appendix")) {
|
|
1618
|
+
currentValue = line.substring(12).trim();
|
|
1619
|
+
continue;
|
|
1620
|
+
}
|
|
1621
|
+
if (line === "```json" || line === "```") {
|
|
1622
|
+
if (inCodeBlock) {
|
|
1623
|
+
inCodeBlock = false;
|
|
1624
|
+
if (currentKey && codeBlockContent.length > 0) {
|
|
1625
|
+
currentValue = codeBlockContent.join("\n");
|
|
1626
|
+
}
|
|
1627
|
+
codeBlockContent = [];
|
|
1628
|
+
} else {
|
|
1629
|
+
inCodeBlock = true;
|
|
1630
|
+
}
|
|
1631
|
+
continue;
|
|
1632
|
+
}
|
|
1633
|
+
if (inCodeBlock) {
|
|
1634
|
+
codeBlockContent.push(line);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
if (currentKey && currentValue !== null) {
|
|
1638
|
+
this.set_value(currentKey, currentValue, currentAttributes);
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* Set base64 binary data.
|
|
1643
|
+
*/
|
|
1644
|
+
set_base64(key, base64Data, contentType, type = "file", attributes) {
|
|
1645
|
+
if (!this.validateContentType(type, contentType)) {
|
|
1646
|
+
throw new Error(`Invalid content type ${contentType} for type ${type}`);
|
|
1647
|
+
}
|
|
1648
|
+
const fileAttributes = {
|
|
1649
|
+
type,
|
|
1650
|
+
contentType,
|
|
1651
|
+
...attributes
|
|
1652
|
+
};
|
|
1653
|
+
this.set_value(key, base64Data, fileAttributes);
|
|
1654
|
+
}
|
|
1655
|
+
/**
|
|
1656
|
+
* Add an image from base64 data.
|
|
1657
|
+
*/
|
|
1658
|
+
add_image(key, base64Data, contentType = "image/jpeg", attributes) {
|
|
1659
|
+
if (!contentType.startsWith("image/")) {
|
|
1660
|
+
throw new Error(`Invalid image content type: ${contentType}. Must start with 'image/'`);
|
|
1661
|
+
}
|
|
1662
|
+
this.set_base64(key, base64Data, contentType, "image", attributes);
|
|
1663
|
+
}
|
|
1664
|
+
/**
|
|
1665
|
+
* Get the data URL for an image or file key.
|
|
1666
|
+
*/
|
|
1667
|
+
get_data_url(key) {
|
|
1668
|
+
const entryMap = this.rootMap.get(key);
|
|
1669
|
+
if (!entryMap) {
|
|
1670
|
+
return void 0;
|
|
1671
|
+
}
|
|
1672
|
+
const attributes = entryMap.get("attributes");
|
|
1673
|
+
if (attributes?.type !== "image" && attributes?.type !== "file") {
|
|
1674
|
+
return void 0;
|
|
1675
|
+
}
|
|
1676
|
+
if (!attributes?.contentType) {
|
|
1677
|
+
return void 0;
|
|
1678
|
+
}
|
|
1679
|
+
const value = entryMap.get("value");
|
|
1680
|
+
return this.createDataUrl(value, attributes.contentType);
|
|
1681
|
+
}
|
|
1682
|
+
/**
|
|
1683
|
+
* Get the base64 data for an image or file key.
|
|
1684
|
+
*/
|
|
1685
|
+
get_base64(key) {
|
|
1686
|
+
const entryMap = this.rootMap.get(key);
|
|
1687
|
+
if (!entryMap) {
|
|
1688
|
+
return void 0;
|
|
1689
|
+
}
|
|
1690
|
+
const attributes = entryMap.get("attributes");
|
|
1691
|
+
if (attributes?.type !== "image" && attributes?.type !== "file") {
|
|
1692
|
+
return void 0;
|
|
1693
|
+
}
|
|
1694
|
+
return entryMap.get("value");
|
|
1695
|
+
}
|
|
994
1696
|
// File methods
|
|
995
1697
|
async set_file(key, file, attributes) {
|
|
996
1698
|
const base64 = await this.encodeFileToBase64(file);
|
|
@@ -1311,10 +2013,14 @@ var MindCache = class {
|
|
|
1311
2013
|
const sanitizedKey = this.sanitizeKeyForTool(key);
|
|
1312
2014
|
if (isWritable) {
|
|
1313
2015
|
if (isDocument) {
|
|
1314
|
-
lines.push(
|
|
2016
|
+
lines.push(
|
|
2017
|
+
`${key}: ${displayValue}. Document tools: write_${sanitizedKey}, append_${sanitizedKey}, edit_${sanitizedKey}`
|
|
2018
|
+
);
|
|
1315
2019
|
} else {
|
|
1316
2020
|
const oldValueHint = displayValue ? ` This tool DOES NOT append \u2014 start your response with the old value (${displayValue})` : "";
|
|
1317
|
-
lines.push(
|
|
2021
|
+
lines.push(
|
|
2022
|
+
`${key}: ${displayValue}. You can rewrite "${key}" by using the write_${sanitizedKey} tool.${oldValueHint}`
|
|
2023
|
+
);
|
|
1318
2024
|
}
|
|
1319
2025
|
} else {
|
|
1320
2026
|
lines.push(`${key}: ${displayValue}`);
|