dotmem 0.0.4 → 0.0.5
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/cli.cjs +934 -33
- package/cli.js +958 -57
- package/global.cjs +1319 -30
- package/global.js +1344 -55
- package/index.cjs +1326 -37
- package/index.js +1350 -61
- package/mcp.cjs +1326 -37
- package/mcp.js +1350 -61
- package/package.json +1 -1
- package/AGENTS.md +0 -464
- package/CHANGELOG.md +0 -0
- package/COPYRIGHT.md +0 -4
- package/LICENSE.md +0 -11
- package/MEMORY.md +0 -518
- package/PACKAGE.md +0 -59
- package/README.md +0 -347
- package/SECURITY.md +0 -524
- package/llms.txt +0 -295
package/mcp.cjs
CHANGED
|
@@ -5064,13 +5064,13 @@ var init_mem_repository = __esm({
|
|
|
5064
5064
|
});
|
|
5065
5065
|
}
|
|
5066
5066
|
async loadSources(sourceIds) {
|
|
5067
|
-
const { readFile:
|
|
5067
|
+
const { readFile: readFile5 } = await nodeFs4();
|
|
5068
5068
|
const ids = sourceIds ?? await this.discover();
|
|
5069
5069
|
const sources = [];
|
|
5070
5070
|
for (const sourceId of ids) {
|
|
5071
5071
|
const filePath = memFilePath(this.directoryPath, sourceId);
|
|
5072
5072
|
try {
|
|
5073
|
-
const decoded = await parseMemFile(await
|
|
5073
|
+
const decoded = await parseMemFile(await readFile5(filePath), sourceId);
|
|
5074
5074
|
sources.push({
|
|
5075
5075
|
id: sourceId,
|
|
5076
5076
|
filePath,
|
|
@@ -5154,10 +5154,10 @@ var init_mem_repository = __esm({
|
|
|
5154
5154
|
* valid package, so the backup is always a version this library can read.
|
|
5155
5155
|
*/
|
|
5156
5156
|
async keepLastValidVersion(filePath) {
|
|
5157
|
-
const { readFile:
|
|
5157
|
+
const { readFile: readFile5, copyFile, rename, rm } = await nodeFs4();
|
|
5158
5158
|
let current;
|
|
5159
5159
|
try {
|
|
5160
|
-
current = await
|
|
5160
|
+
current = await readFile5(filePath);
|
|
5161
5161
|
} catch {
|
|
5162
5162
|
return;
|
|
5163
5163
|
}
|
|
@@ -5190,7 +5190,7 @@ var init_mem_repository = __esm({
|
|
|
5190
5190
|
}
|
|
5191
5191
|
}
|
|
5192
5192
|
async writeSource(filePath, state2, preserved, preservedPackage) {
|
|
5193
|
-
const { mkdir, rename, rm, open: open2, readFile:
|
|
5193
|
+
const { mkdir, rename, rm, open: open2, readFile: readFile5 } = await nodeFs4();
|
|
5194
5194
|
if (!Number.isInteger(state2.version) || state2.version < 0) throw new Error("Invalid writable .mem knowledge version");
|
|
5195
5195
|
for (const claim2 of state2.claims) validateClaim(claim2);
|
|
5196
5196
|
await mkdir(parentPath(filePath), { recursive: true });
|
|
@@ -5212,7 +5212,7 @@ var init_mem_repository = __esm({
|
|
|
5212
5212
|
} finally {
|
|
5213
5213
|
await handle.close();
|
|
5214
5214
|
}
|
|
5215
|
-
await decodeMemArtifact(await
|
|
5215
|
+
await decodeMemArtifact(await readFile5(temporary));
|
|
5216
5216
|
await this.keepLastValidVersion(filePath);
|
|
5217
5217
|
for (let attempt = 0; attempt < 5; attempt++) {
|
|
5218
5218
|
try {
|
|
@@ -5240,8 +5240,8 @@ var init_mem_repository = __esm({
|
|
|
5240
5240
|
// core/knowledge/project-anchor.ts
|
|
5241
5241
|
async function projectAnchorExists(projectId) {
|
|
5242
5242
|
try {
|
|
5243
|
-
const { readFile:
|
|
5244
|
-
await
|
|
5243
|
+
const { readFile: readFile5 } = await import('fs/promises');
|
|
5244
|
+
await readFile5(resolveUserProjectMemoryPath(projectId));
|
|
5245
5245
|
return true;
|
|
5246
5246
|
} catch {
|
|
5247
5247
|
return false;
|
|
@@ -5277,7 +5277,7 @@ var init_project_anchor = __esm({
|
|
|
5277
5277
|
var configureUserIdentityStore;
|
|
5278
5278
|
var init_user_identity = __esm({
|
|
5279
5279
|
"core/knowledge/user-identity.ts"() {
|
|
5280
|
-
configureUserIdentityStore = /* @__PURE__ */ __name((
|
|
5280
|
+
configureUserIdentityStore = /* @__PURE__ */ __name((store6) => {
|
|
5281
5281
|
}, "configureUserIdentityStore");
|
|
5282
5282
|
}
|
|
5283
5283
|
});
|
|
@@ -5881,9 +5881,155 @@ var init_staging = __esm({
|
|
|
5881
5881
|
});
|
|
5882
5882
|
|
|
5883
5883
|
// core/knowledge/loops.ts
|
|
5884
|
+
function joinPath3(base, child) {
|
|
5885
|
+
const separator3 = process.platform === "win32" ? "\\" : "/";
|
|
5886
|
+
return `${base.replace(/[\\/]+/g, separator3)}${separator3}${child}`;
|
|
5887
|
+
}
|
|
5888
|
+
function resolveLoopsFilePath() {
|
|
5889
|
+
return joinPath3(resolveUserDotMemPath(), LOOPS_FILE_NAME);
|
|
5890
|
+
}
|
|
5891
|
+
async function readFile(path) {
|
|
5892
|
+
try {
|
|
5893
|
+
const fs = await import('fs/promises');
|
|
5894
|
+
return await fs.readFile(path, "utf8");
|
|
5895
|
+
} catch {
|
|
5896
|
+
return null;
|
|
5897
|
+
}
|
|
5898
|
+
}
|
|
5899
|
+
async function writeFile(path, content) {
|
|
5900
|
+
const fs = await import('fs/promises');
|
|
5901
|
+
const dir = path.replace(/[\\/][^\\/]+$/, "");
|
|
5902
|
+
await fs.mkdir(dir, { recursive: true });
|
|
5903
|
+
const temporary = `${path}.${process.pid}.${Date.now().toString(36)}.tmp`;
|
|
5904
|
+
try {
|
|
5905
|
+
await fs.writeFile(temporary, content, "utf8");
|
|
5906
|
+
await fs.rename(temporary, path);
|
|
5907
|
+
} catch {
|
|
5908
|
+
await fs.rm(temporary, { force: true }).catch(() => void 0);
|
|
5909
|
+
throw new Error(`Failed to write loops file at ${path}`);
|
|
5910
|
+
}
|
|
5911
|
+
}
|
|
5912
|
+
function emptyDocument() {
|
|
5913
|
+
return { version: LOOPS_FORMAT_VERSION, loops: {} };
|
|
5914
|
+
}
|
|
5915
|
+
function validateDocument(value) {
|
|
5916
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5917
|
+
throw new Error("Loops document must be an object");
|
|
5918
|
+
}
|
|
5919
|
+
const document = value;
|
|
5920
|
+
if (document.version !== LOOPS_FORMAT_VERSION) {
|
|
5921
|
+
throw new Error(`Unsupported loops document version: ${String(document.version)}`);
|
|
5922
|
+
}
|
|
5923
|
+
if (!document.loops || typeof document.loops !== "object" || Array.isArray(document.loops)) {
|
|
5924
|
+
throw new Error("Loops document loops must be an object");
|
|
5925
|
+
}
|
|
5926
|
+
const loops = {};
|
|
5927
|
+
for (const [id, loopValue] of Object.entries(document.loops)) {
|
|
5928
|
+
const loop = validateLoop(loopValue, id);
|
|
5929
|
+
loops[loop.id] = loop;
|
|
5930
|
+
}
|
|
5931
|
+
return { version: LOOPS_FORMAT_VERSION, loops };
|
|
5932
|
+
}
|
|
5933
|
+
function validateLoop(value, id) {
|
|
5934
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5935
|
+
throw new Error(`Loop ${id} must be an object`);
|
|
5936
|
+
}
|
|
5937
|
+
const loop = value;
|
|
5938
|
+
if (typeof loop.id !== "string" || !loop.id) {
|
|
5939
|
+
throw new Error(`Loop ${id} requires an id`);
|
|
5940
|
+
}
|
|
5941
|
+
if (typeof loop.text !== "string" || !loop.text) {
|
|
5942
|
+
throw new Error(`Loop ${id} requires non-empty text`);
|
|
5943
|
+
}
|
|
5944
|
+
if (typeof loop.waitor !== "string" || !loop.waitor) {
|
|
5945
|
+
throw new Error(`Loop ${id} requires a waitor`);
|
|
5946
|
+
}
|
|
5947
|
+
if (typeof loop.openedAt !== "string" || !loop.openedAt) {
|
|
5948
|
+
throw new Error(`Loop ${id} requires an openedAt timestamp`);
|
|
5949
|
+
}
|
|
5950
|
+
const result = {
|
|
5951
|
+
id: loop.id,
|
|
5952
|
+
text: loop.text,
|
|
5953
|
+
waitor: loop.waitor,
|
|
5954
|
+
openedAt: loop.openedAt
|
|
5955
|
+
};
|
|
5956
|
+
if (typeof loop.closedAt === "string") result.closedAt = loop.closedAt;
|
|
5957
|
+
if (typeof loop.closedBy === "string") result.closedBy = loop.closedBy;
|
|
5958
|
+
if (typeof loop.closeNote === "string") result.closeNote = loop.closeNote;
|
|
5959
|
+
return result;
|
|
5960
|
+
}
|
|
5961
|
+
async function loadLoops() {
|
|
5962
|
+
const raw = await readFile(resolveLoopsFilePath());
|
|
5963
|
+
if (!raw) return emptyDocument();
|
|
5964
|
+
try {
|
|
5965
|
+
return validateDocument(JSON.parse(raw));
|
|
5966
|
+
} catch {
|
|
5967
|
+
return emptyDocument();
|
|
5968
|
+
}
|
|
5969
|
+
}
|
|
5970
|
+
async function saveLoops(document) {
|
|
5971
|
+
await writeFile(resolveLoopsFilePath(), JSON.stringify(document, null, 2) + "\n");
|
|
5972
|
+
}
|
|
5973
|
+
async function addLoop(input2) {
|
|
5974
|
+
const document = await loadLoops();
|
|
5975
|
+
if (document.loops[input2.id]) {
|
|
5976
|
+
throw new Error(`Loop ${input2.id} already exists`);
|
|
5977
|
+
}
|
|
5978
|
+
const loop = {
|
|
5979
|
+
id: input2.id,
|
|
5980
|
+
text: input2.text,
|
|
5981
|
+
waitor: input2.waitor,
|
|
5982
|
+
openedAt: input2.openedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
5983
|
+
};
|
|
5984
|
+
document.loops[loop.id] = loop;
|
|
5985
|
+
await saveLoops(document);
|
|
5986
|
+
return loop;
|
|
5987
|
+
}
|
|
5988
|
+
async function listLoops(openOnly = true) {
|
|
5989
|
+
const document = await loadLoops();
|
|
5990
|
+
const all = Object.values(document.loops);
|
|
5991
|
+
if (openOnly) {
|
|
5992
|
+
return all.filter((loop) => loop.closedAt === void 0);
|
|
5993
|
+
}
|
|
5994
|
+
return all;
|
|
5995
|
+
}
|
|
5996
|
+
async function closeLoop(id, input2) {
|
|
5997
|
+
const document = await loadLoops();
|
|
5998
|
+
const existing = document.loops[id];
|
|
5999
|
+
if (!existing) {
|
|
6000
|
+
throw new Error(`Loop ${id} not found`);
|
|
6001
|
+
}
|
|
6002
|
+
if (existing.closedAt) {
|
|
6003
|
+
throw new Error(`Loop ${id} is already closed`);
|
|
6004
|
+
}
|
|
6005
|
+
const closed = {
|
|
6006
|
+
...existing,
|
|
6007
|
+
closedAt: input2.closedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
6008
|
+
closedBy: input2.by,
|
|
6009
|
+
...input2.note ? { closeNote: input2.note } : {}
|
|
6010
|
+
};
|
|
6011
|
+
document.loops[id] = closed;
|
|
6012
|
+
await saveLoops(document);
|
|
6013
|
+
return closed;
|
|
6014
|
+
}
|
|
6015
|
+
var LOOPS_FILE_NAME, LOOPS_FORMAT_VERSION;
|
|
5884
6016
|
var init_loops = __esm({
|
|
5885
6017
|
"core/knowledge/loops.ts"() {
|
|
5886
6018
|
init_user_paths();
|
|
6019
|
+
LOOPS_FILE_NAME = "loops.json";
|
|
6020
|
+
LOOPS_FORMAT_VERSION = 1;
|
|
6021
|
+
__name(joinPath3, "joinPath");
|
|
6022
|
+
__name(resolveLoopsFilePath, "resolveLoopsFilePath");
|
|
6023
|
+
__name(readFile, "readFile");
|
|
6024
|
+
__name(writeFile, "writeFile");
|
|
6025
|
+
__name(emptyDocument, "emptyDocument");
|
|
6026
|
+
__name(validateDocument, "validateDocument");
|
|
6027
|
+
__name(validateLoop, "validateLoop");
|
|
6028
|
+
__name(loadLoops, "loadLoops");
|
|
6029
|
+
__name(saveLoops, "saveLoops");
|
|
6030
|
+
__name(addLoop, "addLoop");
|
|
6031
|
+
__name(listLoops, "listLoops");
|
|
6032
|
+
__name(closeLoop, "closeLoop");
|
|
5887
6033
|
}
|
|
5888
6034
|
});
|
|
5889
6035
|
|
|
@@ -6012,14 +6158,14 @@ var init_violations = __esm({
|
|
|
6012
6158
|
});
|
|
6013
6159
|
|
|
6014
6160
|
// core/knowledge/session.ts
|
|
6015
|
-
function
|
|
6161
|
+
function joinPath4(base, child) {
|
|
6016
6162
|
const separator3 = process.platform === "win32" ? "\\" : "/";
|
|
6017
6163
|
return `${base.replace(/[\\/]+/g, separator3)}${separator3}${child}`;
|
|
6018
6164
|
}
|
|
6019
6165
|
function resolveSessionFilePath() {
|
|
6020
|
-
return
|
|
6166
|
+
return joinPath4(resolveUserDotMemPath(), SESSION_FILE_NAME);
|
|
6021
6167
|
}
|
|
6022
|
-
async function
|
|
6168
|
+
async function readFile2(path) {
|
|
6023
6169
|
try {
|
|
6024
6170
|
const fs = await import('fs/promises');
|
|
6025
6171
|
return await fs.readFile(path, "utf8");
|
|
@@ -6028,7 +6174,7 @@ async function readFile(path) {
|
|
|
6028
6174
|
}
|
|
6029
6175
|
}
|
|
6030
6176
|
async function loadSession() {
|
|
6031
|
-
const raw = await
|
|
6177
|
+
const raw = await readFile2(resolveSessionFilePath());
|
|
6032
6178
|
if (!raw) return { ...DEFAULT_SESSION };
|
|
6033
6179
|
try {
|
|
6034
6180
|
const parsed = JSON.parse(raw);
|
|
@@ -6050,9 +6196,9 @@ var init_session = __esm({
|
|
|
6050
6196
|
"core/knowledge/session.ts"() {
|
|
6051
6197
|
init_user_paths();
|
|
6052
6198
|
SESSION_FILE_NAME = "session.json";
|
|
6053
|
-
__name(
|
|
6199
|
+
__name(joinPath4, "joinPath");
|
|
6054
6200
|
__name(resolveSessionFilePath, "resolveSessionFilePath");
|
|
6055
|
-
__name(
|
|
6201
|
+
__name(readFile2, "readFile");
|
|
6056
6202
|
DEFAULT_SESSION = {
|
|
6057
6203
|
doing: "",
|
|
6058
6204
|
changedFiles: [],
|
|
@@ -6065,16 +6211,368 @@ var init_session = __esm({
|
|
|
6065
6211
|
});
|
|
6066
6212
|
|
|
6067
6213
|
// core/knowledge/exemplars.ts
|
|
6214
|
+
function joinPath5(base, child) {
|
|
6215
|
+
const separator3 = process.platform === "win32" ? "\\" : "/";
|
|
6216
|
+
return `${base.replace(/[\\/]+/g, separator3)}${separator3}${child}`;
|
|
6217
|
+
}
|
|
6218
|
+
function resolveExemplarsPath() {
|
|
6219
|
+
return joinPath5(resolveUserDotMemPath(), EXEMPLARS_FILE_NAME);
|
|
6220
|
+
}
|
|
6221
|
+
async function readFile3(path) {
|
|
6222
|
+
try {
|
|
6223
|
+
const fs = await import('fs/promises');
|
|
6224
|
+
return await fs.readFile(path, "utf8");
|
|
6225
|
+
} catch {
|
|
6226
|
+
return null;
|
|
6227
|
+
}
|
|
6228
|
+
}
|
|
6229
|
+
async function writeFile2(path, content) {
|
|
6230
|
+
const fs = await import('fs/promises');
|
|
6231
|
+
const dir = path.replace(/[\\/][^\\/]+$/, "");
|
|
6232
|
+
await fs.mkdir(dir, { recursive: true });
|
|
6233
|
+
const temporary = `${path}.${process.pid}.${Date.now().toString(36)}.tmp`;
|
|
6234
|
+
try {
|
|
6235
|
+
await fs.writeFile(temporary, content, "utf8");
|
|
6236
|
+
await fs.rename(temporary, path);
|
|
6237
|
+
} catch {
|
|
6238
|
+
await fs.rm(temporary, { force: true }).catch(() => void 0);
|
|
6239
|
+
throw new Error(`Failed to write exemplars file at ${path}`);
|
|
6240
|
+
}
|
|
6241
|
+
}
|
|
6242
|
+
function emptyStore() {
|
|
6243
|
+
return { version: EXEMPLARS_FORMAT_VERSION, exemplars: {} };
|
|
6244
|
+
}
|
|
6245
|
+
function validateExemplar(value) {
|
|
6246
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6247
|
+
throw new Error("Exemplar must be an object");
|
|
6248
|
+
}
|
|
6249
|
+
const e = value;
|
|
6250
|
+
if (typeof e.id !== "string" || !e.id) throw new Error("Exemplar requires non-empty id");
|
|
6251
|
+
if (typeof e.pattern !== "string" || !e.pattern) {
|
|
6252
|
+
throw new Error(`Exemplar ${e.id} requires non-empty pattern`);
|
|
6253
|
+
}
|
|
6254
|
+
const source = e.source ?? {};
|
|
6255
|
+
if (typeof source.conversationId !== "string" || !source.conversationId) {
|
|
6256
|
+
throw new Error(`Exemplar ${e.id} requires source.conversationId`);
|
|
6257
|
+
}
|
|
6258
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
6259
|
+
return {
|
|
6260
|
+
id: e.id,
|
|
6261
|
+
type: "interaction-exemplar",
|
|
6262
|
+
source: {
|
|
6263
|
+
conversationId: source.conversationId,
|
|
6264
|
+
messageIds: Array.isArray(source.messageIds) ? source.messageIds.map(String) : [],
|
|
6265
|
+
...typeof source.timestamp === "string" ? { timestamp: source.timestamp } : {}
|
|
6266
|
+
},
|
|
6267
|
+
pattern: e.pattern,
|
|
6268
|
+
originalContent: typeof e.originalContent === "string" ? e.originalContent : null,
|
|
6269
|
+
sourceReference: typeof e.sourceReference === "string" ? e.sourceReference : null,
|
|
6270
|
+
retrievalHints: Array.isArray(e.retrievalHints) ? e.retrievalHints.map(String) : [],
|
|
6271
|
+
significance: typeof e.significance === "number" && e.significance >= 0 ? e.significance : 0,
|
|
6272
|
+
confidence: typeof e.confidence === "number" && e.confidence >= 0 && e.confidence <= 1 ? e.confidence : 0,
|
|
6273
|
+
provenance: ["human-stated", "observed", "inferred"].includes(
|
|
6274
|
+
e.provenance
|
|
6275
|
+
) ? e.provenance : "observed",
|
|
6276
|
+
createdAt: typeof e.createdAt === "string" ? e.createdAt : now2,
|
|
6277
|
+
revision: typeof e.revision === "number" && e.revision > 0 ? e.revision : 1
|
|
6278
|
+
};
|
|
6279
|
+
}
|
|
6280
|
+
function validateStore(value) {
|
|
6281
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6282
|
+
throw new Error("Exemplars document must be an object");
|
|
6283
|
+
}
|
|
6284
|
+
const doc = value;
|
|
6285
|
+
if (doc.version !== EXEMPLARS_FORMAT_VERSION) {
|
|
6286
|
+
throw new Error(`Unsupported exemplars version: ${String(doc.version)}`);
|
|
6287
|
+
}
|
|
6288
|
+
const exemplars = {};
|
|
6289
|
+
if (doc.exemplars && typeof doc.exemplars === "object" && !Array.isArray(doc.exemplars)) {
|
|
6290
|
+
for (const [_, exemplarValue] of Object.entries(doc.exemplars)) {
|
|
6291
|
+
const exemplar = validateExemplar(exemplarValue);
|
|
6292
|
+
exemplars[exemplar.id] = exemplar;
|
|
6293
|
+
}
|
|
6294
|
+
}
|
|
6295
|
+
return { version: EXEMPLARS_FORMAT_VERSION, exemplars };
|
|
6296
|
+
}
|
|
6297
|
+
async function loadExemplars() {
|
|
6298
|
+
const raw = await readFile3(resolveExemplarsPath());
|
|
6299
|
+
if (raw === null) return emptyStore();
|
|
6300
|
+
try {
|
|
6301
|
+
return validateStore(JSON.parse(raw));
|
|
6302
|
+
} catch {
|
|
6303
|
+
return emptyStore();
|
|
6304
|
+
}
|
|
6305
|
+
}
|
|
6306
|
+
async function saveExemplars(store6) {
|
|
6307
|
+
const validated = validateStore(store6);
|
|
6308
|
+
await writeFile2(resolveExemplarsPath(), JSON.stringify(validated, null, 2));
|
|
6309
|
+
}
|
|
6310
|
+
async function addExemplar(exemplar) {
|
|
6311
|
+
const store6 = await loadExemplars();
|
|
6312
|
+
if (store6.exemplars[exemplar.id]) {
|
|
6313
|
+
throw new Error(`Exemplar ${exemplar.id} already exists`);
|
|
6314
|
+
}
|
|
6315
|
+
if (exemplar.sourceReference) {
|
|
6316
|
+
const existingRef = Object.values(store6.exemplars).find(
|
|
6317
|
+
(e) => e.sourceReference === exemplar.sourceReference
|
|
6318
|
+
);
|
|
6319
|
+
if (existingRef) {
|
|
6320
|
+
throw new Error(`Exemplar with source reference ${exemplar.sourceReference} already exists (id: ${existingRef.id})`);
|
|
6321
|
+
}
|
|
6322
|
+
}
|
|
6323
|
+
const full = {
|
|
6324
|
+
...exemplar,
|
|
6325
|
+
type: "interaction-exemplar",
|
|
6326
|
+
revision: 1
|
|
6327
|
+
};
|
|
6328
|
+
store6.exemplars[exemplar.id] = full;
|
|
6329
|
+
await saveExemplars(store6);
|
|
6330
|
+
return full;
|
|
6331
|
+
}
|
|
6332
|
+
async function updateExemplar(id, updates) {
|
|
6333
|
+
const store6 = await loadExemplars();
|
|
6334
|
+
const existing = store6.exemplars[id];
|
|
6335
|
+
if (!existing) {
|
|
6336
|
+
throw new Error(`Exemplar ${id} not found`);
|
|
6337
|
+
}
|
|
6338
|
+
const updated = {
|
|
6339
|
+
...existing,
|
|
6340
|
+
...updates,
|
|
6341
|
+
id: existing.id,
|
|
6342
|
+
type: "interaction-exemplar",
|
|
6343
|
+
createdAt: existing.createdAt,
|
|
6344
|
+
revision: (updates.revision ?? existing.revision) + 1
|
|
6345
|
+
};
|
|
6346
|
+
store6.exemplars[id] = updated;
|
|
6347
|
+
await saveExemplars(store6);
|
|
6348
|
+
return updated;
|
|
6349
|
+
}
|
|
6350
|
+
var EXEMPLARS_FILE_NAME, EXEMPLARS_FORMAT_VERSION;
|
|
6068
6351
|
var init_exemplars = __esm({
|
|
6069
6352
|
"core/knowledge/exemplars.ts"() {
|
|
6070
6353
|
init_user_paths();
|
|
6354
|
+
EXEMPLARS_FILE_NAME = "exemplars.json";
|
|
6355
|
+
EXEMPLARS_FORMAT_VERSION = 1;
|
|
6356
|
+
__name(joinPath5, "joinPath");
|
|
6357
|
+
__name(resolveExemplarsPath, "resolveExemplarsPath");
|
|
6358
|
+
__name(readFile3, "readFile");
|
|
6359
|
+
__name(writeFile2, "writeFile");
|
|
6360
|
+
__name(emptyStore, "emptyStore");
|
|
6361
|
+
__name(validateExemplar, "validateExemplar");
|
|
6362
|
+
__name(validateStore, "validateStore");
|
|
6363
|
+
__name(loadExemplars, "loadExemplars");
|
|
6364
|
+
__name(saveExemplars, "saveExemplars");
|
|
6365
|
+
__name(addExemplar, "addExemplar");
|
|
6366
|
+
__name(updateExemplar, "updateExemplar");
|
|
6071
6367
|
}
|
|
6072
6368
|
});
|
|
6073
6369
|
|
|
6074
6370
|
// core/knowledge/personality-anchor.ts
|
|
6371
|
+
function joinPath6(base, child) {
|
|
6372
|
+
const separator3 = process.platform === "win32" ? "\\" : "/";
|
|
6373
|
+
return `${base.replace(/[\\/]+/g, separator3)}${separator3}${child}`;
|
|
6374
|
+
}
|
|
6375
|
+
function resolvePersonalityAnchorPath() {
|
|
6376
|
+
return joinPath6(resolveUserDotMemPath(), PERSONALITY_ANCHOR_FILE_NAME);
|
|
6377
|
+
}
|
|
6378
|
+
async function readFile4(path) {
|
|
6379
|
+
try {
|
|
6380
|
+
const fs = await import('fs/promises');
|
|
6381
|
+
return await fs.readFile(path, "utf8");
|
|
6382
|
+
} catch {
|
|
6383
|
+
return null;
|
|
6384
|
+
}
|
|
6385
|
+
}
|
|
6386
|
+
async function writeFile3(path, content) {
|
|
6387
|
+
const fs = await import('fs/promises');
|
|
6388
|
+
const dir = path.replace(/[\\/][^\\/]+$/, "");
|
|
6389
|
+
await fs.mkdir(dir, { recursive: true });
|
|
6390
|
+
const temporary = `${path}.${process.pid}.${Date.now().toString(36)}.tmp`;
|
|
6391
|
+
try {
|
|
6392
|
+
await fs.writeFile(temporary, content, "utf8");
|
|
6393
|
+
await fs.rename(temporary, path);
|
|
6394
|
+
} catch {
|
|
6395
|
+
await fs.rm(temporary, { force: true }).catch(() => void 0);
|
|
6396
|
+
throw new Error(`Failed to write personality anchor at ${path}`);
|
|
6397
|
+
}
|
|
6398
|
+
}
|
|
6399
|
+
function emptyAnchor() {
|
|
6400
|
+
const epoch = "1970-01-01T00:00:00.000Z";
|
|
6401
|
+
return {
|
|
6402
|
+
version: PERSONALITY_ANCHOR_FORMAT_VERSION,
|
|
6403
|
+
identity: {
|
|
6404
|
+
communicationStyle: [],
|
|
6405
|
+
durablePreferences: [],
|
|
6406
|
+
interactionBoundaries: []
|
|
6407
|
+
},
|
|
6408
|
+
metadata: {
|
|
6409
|
+
createdAt: epoch,
|
|
6410
|
+
updatedAt: epoch,
|
|
6411
|
+
revision: 1,
|
|
6412
|
+
sourceReferences: []
|
|
6413
|
+
}
|
|
6414
|
+
};
|
|
6415
|
+
}
|
|
6416
|
+
function validateCommunicationStyle(value) {
|
|
6417
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6418
|
+
throw new Error("communicationStyle entry must be an object");
|
|
6419
|
+
}
|
|
6420
|
+
const style = value;
|
|
6421
|
+
if (typeof style.description !== "string" || !style.description) {
|
|
6422
|
+
throw new Error("communicationStyle entry requires non-empty description");
|
|
6423
|
+
}
|
|
6424
|
+
const confidence = style.confidence ?? "inferred";
|
|
6425
|
+
if (!["inferred", "observed", "human-stated"].includes(confidence)) {
|
|
6426
|
+
throw new Error(`Invalid confidence value: ${String(style.confidence)}`);
|
|
6427
|
+
}
|
|
6428
|
+
const evidence = Array.isArray(style.evidence) ? style.evidence.map(String) : [];
|
|
6429
|
+
return {
|
|
6430
|
+
description: style.description,
|
|
6431
|
+
confidence,
|
|
6432
|
+
evidence,
|
|
6433
|
+
lastObserved: typeof style.lastObserved === "string" ? style.lastObserved : (/* @__PURE__ */ new Date()).toISOString()
|
|
6434
|
+
};
|
|
6435
|
+
}
|
|
6436
|
+
function validateDurablePreference(value) {
|
|
6437
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6438
|
+
throw new Error("durablePreference entry must be an object");
|
|
6439
|
+
}
|
|
6440
|
+
const pref = value;
|
|
6441
|
+
if (typeof pref.id !== "string" || !pref.id) {
|
|
6442
|
+
throw new Error("durablePreference entry requires non-empty id");
|
|
6443
|
+
}
|
|
6444
|
+
if (typeof pref.statement !== "string" || !pref.statement) {
|
|
6445
|
+
throw new Error(`durablePreference ${pref.id} requires non-empty statement`);
|
|
6446
|
+
}
|
|
6447
|
+
const confidence = pref.confidence ?? "inferred";
|
|
6448
|
+
if (!["inferred", "observed", "human-stated"].includes(confidence)) {
|
|
6449
|
+
throw new Error(`Invalid confidence value: ${String(pref.confidence)}`);
|
|
6450
|
+
}
|
|
6451
|
+
const evidence = Array.isArray(pref.evidence) ? pref.evidence.map(String) : [];
|
|
6452
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
6453
|
+
return {
|
|
6454
|
+
id: pref.id,
|
|
6455
|
+
statement: pref.statement,
|
|
6456
|
+
confidence,
|
|
6457
|
+
evidence,
|
|
6458
|
+
firstObserved: typeof pref.firstObserved === "string" ? pref.firstObserved : now2,
|
|
6459
|
+
lastConfirmed: typeof pref.lastConfirmed === "string" ? pref.lastConfirmed : now2,
|
|
6460
|
+
...typeof pref.supersededBy === "string" ? { supersededBy: pref.supersededBy } : {}
|
|
6461
|
+
};
|
|
6462
|
+
}
|
|
6463
|
+
function validateInteractionBoundary(value) {
|
|
6464
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6465
|
+
throw new Error("interactionBoundary entry must be an object");
|
|
6466
|
+
}
|
|
6467
|
+
const boundary = value;
|
|
6468
|
+
if (typeof boundary.id !== "string" || !boundary.id) {
|
|
6469
|
+
throw new Error("interactionBoundary entry requires non-empty id");
|
|
6470
|
+
}
|
|
6471
|
+
if (typeof boundary.rule !== "string" || !boundary.rule) {
|
|
6472
|
+
throw new Error(`interactionBoundary ${boundary.id} requires non-empty rule`);
|
|
6473
|
+
}
|
|
6474
|
+
const confidence = boundary.confidence ?? "inferred";
|
|
6475
|
+
if (!["inferred", "observed", "human-stated"].includes(confidence)) {
|
|
6476
|
+
throw new Error(`Invalid confidence value: ${String(boundary.confidence)}`);
|
|
6477
|
+
}
|
|
6478
|
+
const evidence = Array.isArray(boundary.evidence) ? boundary.evidence.map(String) : [];
|
|
6479
|
+
const source = boundary.source ?? "conversation";
|
|
6480
|
+
if (!["profile", "memory", "conversation"].includes(source)) {
|
|
6481
|
+
throw new Error(`Invalid boundary source: ${String(boundary.source)}`);
|
|
6482
|
+
}
|
|
6483
|
+
return {
|
|
6484
|
+
id: boundary.id,
|
|
6485
|
+
rule: boundary.rule,
|
|
6486
|
+
confidence,
|
|
6487
|
+
evidence,
|
|
6488
|
+
source,
|
|
6489
|
+
lastConfirmed: typeof boundary.lastConfirmed === "string" ? boundary.lastConfirmed : (/* @__PURE__ */ new Date()).toISOString()
|
|
6490
|
+
};
|
|
6491
|
+
}
|
|
6492
|
+
function validateAnchor(value) {
|
|
6493
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
6494
|
+
throw new Error("Personality anchor document must be an object");
|
|
6495
|
+
}
|
|
6496
|
+
const doc = value;
|
|
6497
|
+
if (doc.version !== PERSONALITY_ANCHOR_FORMAT_VERSION) {
|
|
6498
|
+
throw new Error(`Unsupported personality anchor version: ${String(doc.version)}`);
|
|
6499
|
+
}
|
|
6500
|
+
const identity = doc.identity ?? {};
|
|
6501
|
+
const metadata = doc.metadata ?? {};
|
|
6502
|
+
const communicationStyle = Array.isArray(identity.communicationStyle) ? identity.communicationStyle.map(validateCommunicationStyle) : [];
|
|
6503
|
+
const durablePreferences = Array.isArray(identity.durablePreferences) ? identity.durablePreferences.map(validateDurablePreference) : [];
|
|
6504
|
+
const interactionBoundaries = Array.isArray(identity.interactionBoundaries) ? identity.interactionBoundaries.map(validateInteractionBoundary) : [];
|
|
6505
|
+
const sourceRefs = Array.isArray(metadata.sourceReferences) ? metadata.sourceReferences.map(String) : [];
|
|
6506
|
+
return {
|
|
6507
|
+
version: PERSONALITY_ANCHOR_FORMAT_VERSION,
|
|
6508
|
+
identity: {
|
|
6509
|
+
communicationStyle,
|
|
6510
|
+
durablePreferences,
|
|
6511
|
+
interactionBoundaries
|
|
6512
|
+
},
|
|
6513
|
+
metadata: {
|
|
6514
|
+
createdAt: typeof metadata.createdAt === "string" ? metadata.createdAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
6515
|
+
updatedAt: typeof metadata.updatedAt === "string" ? metadata.updatedAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
6516
|
+
revision: typeof metadata.revision === "number" && metadata.revision > 0 ? metadata.revision : 1,
|
|
6517
|
+
sourceReferences: sourceRefs
|
|
6518
|
+
}
|
|
6519
|
+
};
|
|
6520
|
+
}
|
|
6521
|
+
async function loadPersonalityAnchor() {
|
|
6522
|
+
const raw = await readFile4(resolvePersonalityAnchorPath());
|
|
6523
|
+
if (raw === null) return emptyAnchor();
|
|
6524
|
+
try {
|
|
6525
|
+
const parsed = JSON.parse(raw);
|
|
6526
|
+
return validateAnchor(parsed);
|
|
6527
|
+
} catch {
|
|
6528
|
+
return emptyAnchor();
|
|
6529
|
+
}
|
|
6530
|
+
}
|
|
6531
|
+
async function savePersonalityAnchor(anchor2) {
|
|
6532
|
+
const validated = validateAnchor(anchor2);
|
|
6533
|
+
const dirPath = resolveUserDotMemPath();
|
|
6534
|
+
const fs = await import('fs/promises');
|
|
6535
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
6536
|
+
await writeFile3(resolvePersonalityAnchorPath(), JSON.stringify(validated, null, 2));
|
|
6537
|
+
}
|
|
6538
|
+
async function updatePersonalityAnchor(updates) {
|
|
6539
|
+
const existing = await loadPersonalityAnchor();
|
|
6540
|
+
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
6541
|
+
const updated = {
|
|
6542
|
+
...existing,
|
|
6543
|
+
identity: {
|
|
6544
|
+
communicationStyle: updates.communicationStyle ?? existing.identity.communicationStyle,
|
|
6545
|
+
durablePreferences: updates.durablePreferences ?? existing.identity.durablePreferences,
|
|
6546
|
+
interactionBoundaries: updates.interactionBoundaries ?? existing.identity.interactionBoundaries
|
|
6547
|
+
},
|
|
6548
|
+
metadata: {
|
|
6549
|
+
...existing.metadata,
|
|
6550
|
+
updatedAt: now2,
|
|
6551
|
+
revision: existing.metadata.revision + 1,
|
|
6552
|
+
sourceReferences: updates.sourceReferences ? [.../* @__PURE__ */ new Set([...existing.metadata.sourceReferences, ...updates.sourceReferences])] : existing.metadata.sourceReferences
|
|
6553
|
+
}
|
|
6554
|
+
};
|
|
6555
|
+
await savePersonalityAnchor(updated);
|
|
6556
|
+
return updated;
|
|
6557
|
+
}
|
|
6558
|
+
var PERSONALITY_ANCHOR_FILE_NAME, PERSONALITY_ANCHOR_FORMAT_VERSION;
|
|
6075
6559
|
var init_personality_anchor = __esm({
|
|
6076
6560
|
"core/knowledge/personality-anchor.ts"() {
|
|
6077
6561
|
init_user_paths();
|
|
6562
|
+
PERSONALITY_ANCHOR_FILE_NAME = "personality-anchor.json";
|
|
6563
|
+
PERSONALITY_ANCHOR_FORMAT_VERSION = 1;
|
|
6564
|
+
__name(joinPath6, "joinPath");
|
|
6565
|
+
__name(resolvePersonalityAnchorPath, "resolvePersonalityAnchorPath");
|
|
6566
|
+
__name(readFile4, "readFile");
|
|
6567
|
+
__name(writeFile3, "writeFile");
|
|
6568
|
+
__name(emptyAnchor, "emptyAnchor");
|
|
6569
|
+
__name(validateCommunicationStyle, "validateCommunicationStyle");
|
|
6570
|
+
__name(validateDurablePreference, "validateDurablePreference");
|
|
6571
|
+
__name(validateInteractionBoundary, "validateInteractionBoundary");
|
|
6572
|
+
__name(validateAnchor, "validateAnchor");
|
|
6573
|
+
__name(loadPersonalityAnchor, "loadPersonalityAnchor");
|
|
6574
|
+
__name(savePersonalityAnchor, "savePersonalityAnchor");
|
|
6575
|
+
__name(updatePersonalityAnchor, "updatePersonalityAnchor");
|
|
6078
6576
|
}
|
|
6079
6577
|
});
|
|
6080
6578
|
|
|
@@ -42225,7 +42723,7 @@ var StdioServerTransport = class {
|
|
|
42225
42723
|
|
|
42226
42724
|
// package.json
|
|
42227
42725
|
var package_default = {
|
|
42228
|
-
version: "0.0.
|
|
42726
|
+
version: "0.0.5"};
|
|
42229
42727
|
var g = globalThis;
|
|
42230
42728
|
function namespace() {
|
|
42231
42729
|
const cfg = g.dotmemSyncConfig;
|
|
@@ -42724,27 +43222,27 @@ var auditPolicyAction = /* @__PURE__ */ __name((action, key) => {
|
|
|
42724
43222
|
}
|
|
42725
43223
|
}, "auditPolicyAction");
|
|
42726
43224
|
var resolveOverrides = /* @__PURE__ */ __name(async (namespace2, now2 = () => /* @__PURE__ */ new Date()) => {
|
|
42727
|
-
const
|
|
43225
|
+
const store6 = await getPolicyStore();
|
|
42728
43226
|
const namespaces = namespace2 ? [namespace2] : POLICY_NAMESPACES;
|
|
42729
|
-
const documents = await Promise.all(namespaces.map((entry) =>
|
|
43227
|
+
const documents = await Promise.all(namespaces.map((entry) => store6.load(entry)));
|
|
42730
43228
|
return documents.flatMap((document) => document.overrides.map(
|
|
42731
43229
|
(override) => resolveOverrideState(override, document.records.find((record2) => record2.id === override.targetPolicyId), now2)
|
|
42732
43230
|
)).sort((left, right) => left.override.id.localeCompare(right.override.id));
|
|
42733
43231
|
}, "resolveOverrides");
|
|
42734
43232
|
var policy = {
|
|
42735
43233
|
async assign(input2, namespace2 = "operator", basedOnRevision) {
|
|
42736
|
-
const
|
|
42737
|
-
const record2 = await
|
|
43234
|
+
const store6 = await getPolicyStore();
|
|
43235
|
+
const record2 = await store6.assign(input2, namespace2, basedOnRevision);
|
|
42738
43236
|
auditPolicyAction("policy.assign", record2.id);
|
|
42739
43237
|
return record2;
|
|
42740
43238
|
},
|
|
42741
43239
|
async list() {
|
|
42742
|
-
const
|
|
42743
|
-
return
|
|
43240
|
+
const store6 = await getPolicyStore();
|
|
43241
|
+
return store6.list();
|
|
42744
43242
|
},
|
|
42745
43243
|
async remove(id, namespace2 = "operator", basedOnRevision) {
|
|
42746
|
-
const
|
|
42747
|
-
await
|
|
43244
|
+
const store6 = await getPolicyStore();
|
|
43245
|
+
await store6.remove(id, namespace2, basedOnRevision);
|
|
42748
43246
|
auditPolicyAction("policy.remove", id);
|
|
42749
43247
|
},
|
|
42750
43248
|
/**
|
|
@@ -42758,16 +43256,16 @@ var policy = {
|
|
|
42758
43256
|
* the durable audit trail with a terminal CLEAR entry.
|
|
42759
43257
|
*/
|
|
42760
43258
|
async clear(authority) {
|
|
42761
|
-
const
|
|
42762
|
-
await
|
|
43259
|
+
const store6 = await getPolicyStore();
|
|
43260
|
+
await store6.clear(authority);
|
|
42763
43261
|
auditPolicyAction("policy.clear", "policy");
|
|
42764
43262
|
},
|
|
42765
43263
|
async evaluate(event, payload) {
|
|
42766
|
-
const
|
|
43264
|
+
const store6 = await getPolicyStore();
|
|
42767
43265
|
const [state2, policies, overrides] = await Promise.all([
|
|
42768
43266
|
loadCombinedKnowledgeState(),
|
|
42769
|
-
|
|
42770
|
-
|
|
43267
|
+
store6.list(),
|
|
43268
|
+
store6.listOverrides()
|
|
42771
43269
|
]);
|
|
42772
43270
|
const claims = activeClaims(state2);
|
|
42773
43271
|
return evaluatePolicies({ event, claims, policies, overrides, payload });
|
|
@@ -42789,14 +43287,14 @@ var policy = {
|
|
|
42789
43287
|
*/
|
|
42790
43288
|
override: {
|
|
42791
43289
|
async grant(input2, namespace2 = "operator", basedOnRevision) {
|
|
42792
|
-
const
|
|
42793
|
-
const override = await
|
|
43290
|
+
const store6 = await getPolicyStore();
|
|
43291
|
+
const override = await store6.grantOverride(input2, namespace2, basedOnRevision);
|
|
42794
43292
|
auditPolicyAction("policy.override", override.id);
|
|
42795
43293
|
return override;
|
|
42796
43294
|
},
|
|
42797
43295
|
async revoke(input2, namespace2 = "operator", basedOnRevision) {
|
|
42798
|
-
const
|
|
42799
|
-
const override = await
|
|
43296
|
+
const store6 = await getPolicyStore();
|
|
43297
|
+
const override = await store6.revokeOverride(input2, namespace2, basedOnRevision);
|
|
42800
43298
|
auditPolicyAction("policy.revoke", override.id);
|
|
42801
43299
|
return override;
|
|
42802
43300
|
},
|
|
@@ -42804,8 +43302,8 @@ var policy = {
|
|
|
42804
43302
|
return resolveOverrides(namespace2);
|
|
42805
43303
|
},
|
|
42806
43304
|
async effective(event, namespace2) {
|
|
42807
|
-
const
|
|
42808
|
-
const states = await
|
|
43305
|
+
const store6 = await getPolicyStore();
|
|
43306
|
+
const states = await store6.effectiveState(namespace2);
|
|
42809
43307
|
if (event === void 0) return states;
|
|
42810
43308
|
const canonical = event.trim();
|
|
42811
43309
|
return states.filter((state2) => state2.event === canonical);
|
|
@@ -42818,8 +43316,8 @@ var policy = {
|
|
|
42818
43316
|
* additional best-effort sink, and this is the durable record.
|
|
42819
43317
|
*/
|
|
42820
43318
|
async audit(namespace2) {
|
|
42821
|
-
const
|
|
42822
|
-
return
|
|
43319
|
+
const store6 = await getPolicyStore();
|
|
43320
|
+
return store6.auditTrail(namespace2);
|
|
42823
43321
|
},
|
|
42824
43322
|
contract() {
|
|
42825
43323
|
return MEMORY_PROJECTION_CONTRACT;
|
|
@@ -43725,6 +44223,778 @@ var injectJoySeed = /* @__PURE__ */ __name(async (opts) => {
|
|
|
43725
44223
|
return { id: seedId, action: "stored" };
|
|
43726
44224
|
}, "injectJoySeed");
|
|
43727
44225
|
|
|
44226
|
+
// core/memory/capture-engine.ts
|
|
44227
|
+
init_exemplars();
|
|
44228
|
+
init_loops();
|
|
44229
|
+
init_personality_anchor();
|
|
44230
|
+
var CAPTURE_STATE_KEY = "__dotmem_capture_state__";
|
|
44231
|
+
var DEFAULT_CONFIG = {
|
|
44232
|
+
minSignificance: 0.3,
|
|
44233
|
+
maxItemsPerConversation: 50,
|
|
44234
|
+
dedupSimilarityThreshold: 0.75,
|
|
44235
|
+
preserveConflicts: true,
|
|
44236
|
+
tempContextTtlMs: 24 * 60 * 60 * 1e3,
|
|
44237
|
+
autoCreateExemplars: true,
|
|
44238
|
+
autoCreateLoops: true,
|
|
44239
|
+
autoCreateClaims: true
|
|
44240
|
+
};
|
|
44241
|
+
var CATEGORY_KEYWORDS = {
|
|
44242
|
+
fact: [
|
|
44243
|
+
"is",
|
|
44244
|
+
"are",
|
|
44245
|
+
"was",
|
|
44246
|
+
"were",
|
|
44247
|
+
"uses",
|
|
44248
|
+
"built with",
|
|
44249
|
+
"depends on",
|
|
44250
|
+
"located at",
|
|
44251
|
+
"named",
|
|
44252
|
+
"called",
|
|
44253
|
+
"version",
|
|
44254
|
+
"language",
|
|
44255
|
+
"framework",
|
|
44256
|
+
"test",
|
|
44257
|
+
"testing"
|
|
44258
|
+
],
|
|
44259
|
+
decision: [
|
|
44260
|
+
"decided",
|
|
44261
|
+
"decision",
|
|
44262
|
+
"agreed",
|
|
44263
|
+
"chose",
|
|
44264
|
+
"selected",
|
|
44265
|
+
"adopt",
|
|
44266
|
+
"going with",
|
|
44267
|
+
"will use",
|
|
44268
|
+
"commit to",
|
|
44269
|
+
"resolve",
|
|
44270
|
+
"settled"
|
|
44271
|
+
],
|
|
44272
|
+
experience: [
|
|
44273
|
+
"remember when",
|
|
44274
|
+
"we talked about",
|
|
44275
|
+
"discussed",
|
|
44276
|
+
"experienced",
|
|
44277
|
+
"encountered",
|
|
44278
|
+
"faced",
|
|
44279
|
+
"went through",
|
|
44280
|
+
"session",
|
|
44281
|
+
"conversation"
|
|
44282
|
+
],
|
|
44283
|
+
question: [
|
|
44284
|
+
"?",
|
|
44285
|
+
"how do",
|
|
44286
|
+
"what is",
|
|
44287
|
+
"why",
|
|
44288
|
+
"when",
|
|
44289
|
+
"where",
|
|
44290
|
+
"which",
|
|
44291
|
+
"can you",
|
|
44292
|
+
"should we",
|
|
44293
|
+
"is it possible"
|
|
44294
|
+
],
|
|
44295
|
+
open_loop: [
|
|
44296
|
+
"still need to",
|
|
44297
|
+
"pending",
|
|
44298
|
+
"waiting for",
|
|
44299
|
+
"todo",
|
|
44300
|
+
"to do",
|
|
44301
|
+
"open",
|
|
44302
|
+
"unresolved",
|
|
44303
|
+
"outstanding",
|
|
44304
|
+
"follow up",
|
|
44305
|
+
"blocked"
|
|
44306
|
+
],
|
|
44307
|
+
preference: [
|
|
44308
|
+
"prefer",
|
|
44309
|
+
"prefers",
|
|
44310
|
+
"like",
|
|
44311
|
+
"likes",
|
|
44312
|
+
"favorite",
|
|
44313
|
+
"always",
|
|
44314
|
+
"never",
|
|
44315
|
+
"don't like",
|
|
44316
|
+
"dislike",
|
|
44317
|
+
"style",
|
|
44318
|
+
"habit"
|
|
44319
|
+
],
|
|
44320
|
+
project_context: [
|
|
44321
|
+
"project",
|
|
44322
|
+
"repository",
|
|
44323
|
+
"codebase",
|
|
44324
|
+
"architecture",
|
|
44325
|
+
"stack",
|
|
44326
|
+
"deploy",
|
|
44327
|
+
"ci",
|
|
44328
|
+
"pipeline",
|
|
44329
|
+
"package"
|
|
44330
|
+
],
|
|
44331
|
+
temporary_context: [
|
|
44332
|
+
"for now",
|
|
44333
|
+
"just for",
|
|
44334
|
+
"temporary",
|
|
44335
|
+
"this session",
|
|
44336
|
+
"currently",
|
|
44337
|
+
"right now",
|
|
44338
|
+
"at the moment",
|
|
44339
|
+
"for this task"
|
|
44340
|
+
],
|
|
44341
|
+
inference: [
|
|
44342
|
+
"probably",
|
|
44343
|
+
"likely",
|
|
44344
|
+
"maybe",
|
|
44345
|
+
"perhaps",
|
|
44346
|
+
"seems",
|
|
44347
|
+
"appears",
|
|
44348
|
+
"suggests",
|
|
44349
|
+
"indicates",
|
|
44350
|
+
"implies",
|
|
44351
|
+
"might",
|
|
44352
|
+
"could be"
|
|
44353
|
+
]
|
|
44354
|
+
};
|
|
44355
|
+
var REMEMBER_PATTERNS = [
|
|
44356
|
+
/remember this/i,
|
|
44357
|
+
/remember that/i,
|
|
44358
|
+
/keep this in mind/i,
|
|
44359
|
+
/don't forget/i,
|
|
44360
|
+
/do not forget/i,
|
|
44361
|
+
/store this/i,
|
|
44362
|
+
/save this/i
|
|
44363
|
+
];
|
|
44364
|
+
var DO_NOT_REMEMBER_PATTERNS = [
|
|
44365
|
+
/don't remember/i,
|
|
44366
|
+
/do not remember/i,
|
|
44367
|
+
/forget this/i,
|
|
44368
|
+
/don't store/i,
|
|
44369
|
+
/do not store/i,
|
|
44370
|
+
/not relevant/i,
|
|
44371
|
+
/ignore this/i,
|
|
44372
|
+
/temporary only/i,
|
|
44373
|
+
/this session only/i
|
|
44374
|
+
];
|
|
44375
|
+
function generateId() {
|
|
44376
|
+
return `capture-${memorio.hlc.serialize(memorio.hlc.tick())}-${Math.random().toString(36).slice(2, 10)}`;
|
|
44377
|
+
}
|
|
44378
|
+
__name(generateId, "generateId");
|
|
44379
|
+
function nowIso() {
|
|
44380
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
44381
|
+
}
|
|
44382
|
+
__name(nowIso, "nowIso");
|
|
44383
|
+
function normalizeText(text) {
|
|
44384
|
+
return text.normalize("NFKC").toLocaleLowerCase("en-US").replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
|
|
44385
|
+
}
|
|
44386
|
+
__name(normalizeText, "normalizeText");
|
|
44387
|
+
function tokenize(text) {
|
|
44388
|
+
return new Set(normalizeText(text).split(" ").filter((t) => t.length > 2));
|
|
44389
|
+
}
|
|
44390
|
+
__name(tokenize, "tokenize");
|
|
44391
|
+
function jaccardSimilarity(a, b) {
|
|
44392
|
+
const ta = tokenize(a);
|
|
44393
|
+
const tb = tokenize(b);
|
|
44394
|
+
if (ta.size === 0 && tb.size === 0) return 1;
|
|
44395
|
+
if (ta.size === 0 || tb.size === 0) return 0;
|
|
44396
|
+
const intersection2 = new Set([...ta].filter((x2) => tb.has(x2)));
|
|
44397
|
+
const union2 = /* @__PURE__ */ new Set([...ta, ...tb]);
|
|
44398
|
+
return intersection2.size / union2.size;
|
|
44399
|
+
}
|
|
44400
|
+
__name(jaccardSimilarity, "jaccardSimilarity");
|
|
44401
|
+
function containsPhrase2(text, phrase) {
|
|
44402
|
+
const t = normalizeText(text);
|
|
44403
|
+
const p = normalizeText(phrase);
|
|
44404
|
+
return t.includes(p);
|
|
44405
|
+
}
|
|
44406
|
+
__name(containsPhrase2, "containsPhrase");
|
|
44407
|
+
function detectExplicitInstructions(text, source) {
|
|
44408
|
+
const instructions = [];
|
|
44409
|
+
for (const pattern of REMEMBER_PATTERNS) {
|
|
44410
|
+
if (pattern.test(text)) {
|
|
44411
|
+
instructions.push({
|
|
44412
|
+
type: "remember",
|
|
44413
|
+
content: text,
|
|
44414
|
+
source,
|
|
44415
|
+
timestamp: nowIso()
|
|
44416
|
+
});
|
|
44417
|
+
break;
|
|
44418
|
+
}
|
|
44419
|
+
}
|
|
44420
|
+
for (const pattern of DO_NOT_REMEMBER_PATTERNS) {
|
|
44421
|
+
if (pattern.test(text)) {
|
|
44422
|
+
instructions.push({
|
|
44423
|
+
type: "do-not-remember",
|
|
44424
|
+
content: text,
|
|
44425
|
+
source,
|
|
44426
|
+
timestamp: nowIso()
|
|
44427
|
+
});
|
|
44428
|
+
break;
|
|
44429
|
+
}
|
|
44430
|
+
}
|
|
44431
|
+
return instructions;
|
|
44432
|
+
}
|
|
44433
|
+
__name(detectExplicitInstructions, "detectExplicitInstructions");
|
|
44434
|
+
function classifyCategory(text, explicitInstructions) {
|
|
44435
|
+
const lower = text.toLocaleLowerCase("en-US");
|
|
44436
|
+
if (explicitInstructions.some((i2) => i2.type === "do-not-remember")) {
|
|
44437
|
+
return "temporary_context";
|
|
44438
|
+
}
|
|
44439
|
+
if (explicitInstructions.some((i2) => i2.type === "remember")) {
|
|
44440
|
+
if (/prefer|prefers|like|likes|favorite|always|never/i.test(lower)) {
|
|
44441
|
+
return "preference";
|
|
44442
|
+
}
|
|
44443
|
+
if (/decided|decision|agreed|chose|adopt/i.test(lower)) {
|
|
44444
|
+
return "decision";
|
|
44445
|
+
}
|
|
44446
|
+
return "fact";
|
|
44447
|
+
}
|
|
44448
|
+
const scores = {};
|
|
44449
|
+
for (const cat of Object.keys(CATEGORY_KEYWORDS)) {
|
|
44450
|
+
scores[cat] = CATEGORY_KEYWORDS[cat].filter((kw) => containsPhrase2(lower, kw)).length;
|
|
44451
|
+
}
|
|
44452
|
+
if (/probably|likely|maybe|perhaps|seems|appears|might|could be/i.test(lower)) {
|
|
44453
|
+
scores.inference += 3;
|
|
44454
|
+
}
|
|
44455
|
+
if (text.includes("?")) {
|
|
44456
|
+
scores.question += 3;
|
|
44457
|
+
}
|
|
44458
|
+
if (/decided|decision|agreed|chose|adopt|will use|going with|resolve|settled/i.test(lower)) {
|
|
44459
|
+
scores.decision += 3;
|
|
44460
|
+
}
|
|
44461
|
+
if (/prefer|prefers|like|likes|favorite|always|never|don.t like|dislike/i.test(lower)) {
|
|
44462
|
+
scores.preference += 3;
|
|
44463
|
+
}
|
|
44464
|
+
if (/still need to|pending|waiting for|todo|to do|unresolved|outstanding|follow.?up|blocked/i.test(lower)) {
|
|
44465
|
+
scores.open_loop += 3;
|
|
44466
|
+
}
|
|
44467
|
+
if (/remember when|we talked about|discussed|experienced|encountered|session|conversation/i.test(lower)) {
|
|
44468
|
+
scores.experience += 2;
|
|
44469
|
+
}
|
|
44470
|
+
if (/repository|architecture|deploy|ci|pipeline/i.test(lower)) {
|
|
44471
|
+
scores.project_context += 2;
|
|
44472
|
+
}
|
|
44473
|
+
if (/just for|this session|for now|temporary/i.test(lower)) {
|
|
44474
|
+
scores.temporary_context += 3;
|
|
44475
|
+
}
|
|
44476
|
+
if (scores.fact > 0 && scores.project_context > 0 && scores.fact === scores.project_context) {
|
|
44477
|
+
scores.fact += 1;
|
|
44478
|
+
}
|
|
44479
|
+
let bestCategory = "fact";
|
|
44480
|
+
let bestScore = -1;
|
|
44481
|
+
for (const [cat, score] of Object.entries(scores)) {
|
|
44482
|
+
if (score > bestScore) {
|
|
44483
|
+
bestScore = score;
|
|
44484
|
+
bestCategory = cat;
|
|
44485
|
+
}
|
|
44486
|
+
}
|
|
44487
|
+
if (bestScore === 0) return "fact";
|
|
44488
|
+
return bestCategory;
|
|
44489
|
+
}
|
|
44490
|
+
__name(classifyCategory, "classifyCategory");
|
|
44491
|
+
function determineEpistemicType(category, text, explicitInstructions) {
|
|
44492
|
+
if (explicitInstructions.some((i2) => i2.type === "remember")) {
|
|
44493
|
+
return "human-stated";
|
|
44494
|
+
}
|
|
44495
|
+
if (category === "inference" || /probably|likely|maybe|perhaps|seems|appears/i.test(text)) {
|
|
44496
|
+
return "inferred";
|
|
44497
|
+
}
|
|
44498
|
+
if (category === "question") return "observed";
|
|
44499
|
+
return "observed";
|
|
44500
|
+
}
|
|
44501
|
+
__name(determineEpistemicType, "determineEpistemicType");
|
|
44502
|
+
function determineConfidence(category, epistemicType, _text) {
|
|
44503
|
+
if (epistemicType === "human-stated") return "high";
|
|
44504
|
+
if (epistemicType === "inferred") return "low";
|
|
44505
|
+
if (category === "decision" || category === "preference") return "medium";
|
|
44506
|
+
if (category === "question") return "medium";
|
|
44507
|
+
if (category === "fact") return "medium";
|
|
44508
|
+
return "low";
|
|
44509
|
+
}
|
|
44510
|
+
__name(determineConfidence, "determineConfidence");
|
|
44511
|
+
function extractEntities(text) {
|
|
44512
|
+
const entities = [];
|
|
44513
|
+
const seen = /* @__PURE__ */ new Set();
|
|
44514
|
+
const capitalizedMatches = text.match(/\b[A-Z][a-zA-Z]+(?:\s+[A-Z][a-zA-Z]+)*\b/g) || [];
|
|
44515
|
+
for (const match of capitalizedMatches) {
|
|
44516
|
+
if (seen.has(match)) continue;
|
|
44517
|
+
seen.add(match);
|
|
44518
|
+
entities.push({
|
|
44519
|
+
id: `entity-${normalizeText(match)}`,
|
|
44520
|
+
type: "concept",
|
|
44521
|
+
name: match,
|
|
44522
|
+
aliases: [],
|
|
44523
|
+
relationships: []
|
|
44524
|
+
});
|
|
44525
|
+
}
|
|
44526
|
+
const quotedMatches = text.match(/["'`]([^"`']{2,})["'`]/g) || [];
|
|
44527
|
+
for (const match of quotedMatches) {
|
|
44528
|
+
const clean = match.replace(/["'`]/g, "");
|
|
44529
|
+
if (seen.has(clean)) continue;
|
|
44530
|
+
seen.add(clean);
|
|
44531
|
+
entities.push({
|
|
44532
|
+
id: `entity-${normalizeText(clean)}`,
|
|
44533
|
+
type: "concept",
|
|
44534
|
+
name: clean,
|
|
44535
|
+
aliases: [],
|
|
44536
|
+
relationships: []
|
|
44537
|
+
});
|
|
44538
|
+
}
|
|
44539
|
+
return entities;
|
|
44540
|
+
}
|
|
44541
|
+
__name(extractEntities, "extractEntities");
|
|
44542
|
+
function extractRelationships(_text, entities) {
|
|
44543
|
+
const relationships = [];
|
|
44544
|
+
if (entities.length < 2) return relationships;
|
|
44545
|
+
for (let i2 = 0; i2 < entities.length - 1; i2++) {
|
|
44546
|
+
for (let j = i2 + 1; j < entities.length; j++) {
|
|
44547
|
+
relationships.push({
|
|
44548
|
+
from: entities[i2].id,
|
|
44549
|
+
to: entities[j].id,
|
|
44550
|
+
type: "related-to",
|
|
44551
|
+
confidence: 0.5
|
|
44552
|
+
});
|
|
44553
|
+
}
|
|
44554
|
+
}
|
|
44555
|
+
return relationships;
|
|
44556
|
+
}
|
|
44557
|
+
__name(extractRelationships, "extractRelationships");
|
|
44558
|
+
async function findExistingSimilarItems(statement, category, existingItems, threshold) {
|
|
44559
|
+
const matches2 = [];
|
|
44560
|
+
for (const existing of existingItems) {
|
|
44561
|
+
if (existing.category !== category) continue;
|
|
44562
|
+
const similarity = jaccardSimilarity(statement, existing.statement);
|
|
44563
|
+
if (similarity >= threshold) {
|
|
44564
|
+
matches2.push({
|
|
44565
|
+
existingId: existing.id,
|
|
44566
|
+
existingStatement: existing.statement,
|
|
44567
|
+
similarity,
|
|
44568
|
+
matchType: similarity >= 0.95 ? "exact" : "semantic",
|
|
44569
|
+
category: existing.category
|
|
44570
|
+
});
|
|
44571
|
+
}
|
|
44572
|
+
}
|
|
44573
|
+
return matches2;
|
|
44574
|
+
}
|
|
44575
|
+
__name(findExistingSimilarItems, "findExistingSimilarItems");
|
|
44576
|
+
async function findExistingMemoryEntries(statement, category) {
|
|
44577
|
+
const matches2 = [];
|
|
44578
|
+
try {
|
|
44579
|
+
const all = await entries._loadAll();
|
|
44580
|
+
for (const entry of all) {
|
|
44581
|
+
if (entry.status !== "active") continue;
|
|
44582
|
+
if (entry.type !== category && entry.type !== "fact") continue;
|
|
44583
|
+
const entryText = typeof entry.value === "string" ? entry.value : JSON.stringify(entry.value);
|
|
44584
|
+
const similarity = jaccardSimilarity(statement, entryText);
|
|
44585
|
+
if (similarity >= DEFAULT_CONFIG.dedupSimilarityThreshold) {
|
|
44586
|
+
matches2.push({
|
|
44587
|
+
existingId: entry.id,
|
|
44588
|
+
existingStatement: entryText,
|
|
44589
|
+
similarity,
|
|
44590
|
+
matchType: similarity >= 0.95 ? "exact" : "semantic",
|
|
44591
|
+
category
|
|
44592
|
+
});
|
|
44593
|
+
}
|
|
44594
|
+
}
|
|
44595
|
+
} catch {
|
|
44596
|
+
}
|
|
44597
|
+
return matches2;
|
|
44598
|
+
}
|
|
44599
|
+
__name(findExistingMemoryEntries, "findExistingMemoryEntries");
|
|
44600
|
+
function shouldStoreInCoreMemory(category, epistemicType) {
|
|
44601
|
+
return category === "preference" && epistemicType === "human-stated";
|
|
44602
|
+
}
|
|
44603
|
+
__name(shouldStoreInCoreMemory, "shouldStoreInCoreMemory");
|
|
44604
|
+
async function routeToStorage(item, adapters, config2) {
|
|
44605
|
+
const { category, epistemicType, statement, entities, provenance, confidence } = item;
|
|
44606
|
+
const memKey = `capture:${item.id}`;
|
|
44607
|
+
await entries.remember(memKey, {
|
|
44608
|
+
id: item.id,
|
|
44609
|
+
category,
|
|
44610
|
+
statement,
|
|
44611
|
+
entities,
|
|
44612
|
+
relationships: item.relationships,
|
|
44613
|
+
provenance,
|
|
44614
|
+
confidence,
|
|
44615
|
+
epistemicType,
|
|
44616
|
+
capturedAt: provenance.capturedAt
|
|
44617
|
+
}, {
|
|
44618
|
+
id: item.id,
|
|
44619
|
+
type: category === "preference" ? "preference" : category === "decision" ? "decision" : category === "fact" ? "fact" : "context",
|
|
44620
|
+
confidence: confidence === "high" ? 1 : confidence === "medium" ? 0.7 : 0.4,
|
|
44621
|
+
scope: category === "temporary_context" ? "session" : "local",
|
|
44622
|
+
tags: [category, provenance.epistemicType, provenance.source.conversationId],
|
|
44623
|
+
source: `capture:${provenance.source.conversationId}`
|
|
44624
|
+
});
|
|
44625
|
+
if (shouldStoreInCoreMemory(category, epistemicType)) {
|
|
44626
|
+
try {
|
|
44627
|
+
const anchor2 = await loadPersonalityAnchor();
|
|
44628
|
+
const existingPref = anchor2.identity.durablePreferences.find((p) => p.statement === statement);
|
|
44629
|
+
if (!existingPref) {
|
|
44630
|
+
await updatePersonalityAnchor({
|
|
44631
|
+
durablePreferences: [
|
|
44632
|
+
...anchor2.identity.durablePreferences,
|
|
44633
|
+
{
|
|
44634
|
+
id: item.id,
|
|
44635
|
+
statement,
|
|
44636
|
+
confidence: epistemicType,
|
|
44637
|
+
evidence: [provenance.source.conversationId],
|
|
44638
|
+
firstObserved: provenance.capturedAt,
|
|
44639
|
+
lastConfirmed: provenance.capturedAt
|
|
44640
|
+
}
|
|
44641
|
+
]
|
|
44642
|
+
});
|
|
44643
|
+
}
|
|
44644
|
+
} catch {
|
|
44645
|
+
}
|
|
44646
|
+
}
|
|
44647
|
+
if (category === "open_loop" && config2.autoCreateLoops) {
|
|
44648
|
+
try {
|
|
44649
|
+
const existingLoops = await listLoops(true);
|
|
44650
|
+
const alreadyExists = existingLoops.some((l) => l.text === statement);
|
|
44651
|
+
if (!alreadyExists) {
|
|
44652
|
+
await addLoop({
|
|
44653
|
+
id: item.id,
|
|
44654
|
+
text: statement,
|
|
44655
|
+
waitor: "joy",
|
|
44656
|
+
openedAt: provenance.capturedAt
|
|
44657
|
+
});
|
|
44658
|
+
}
|
|
44659
|
+
} catch {
|
|
44660
|
+
}
|
|
44661
|
+
}
|
|
44662
|
+
if (category === "experience" && config2.autoCreateExemplars) {
|
|
44663
|
+
try {
|
|
44664
|
+
await addExemplar({
|
|
44665
|
+
id: item.id,
|
|
44666
|
+
source: {
|
|
44667
|
+
conversationId: provenance.source.conversationId,
|
|
44668
|
+
messageIds: provenance.source.messageIds
|
|
44669
|
+
},
|
|
44670
|
+
pattern: statement,
|
|
44671
|
+
originalContent: statement,
|
|
44672
|
+
sourceReference: `capture:${item.id}`,
|
|
44673
|
+
retrievalHints: [statement, ...entities.map((e) => e.name)],
|
|
44674
|
+
significance: confidence === "high" ? 0.8 : confidence === "medium" ? 0.5 : 0.3,
|
|
44675
|
+
confidence: confidence === "high" ? 1 : confidence === "medium" ? 0.7 : 0.4,
|
|
44676
|
+
provenance: epistemicType,
|
|
44677
|
+
createdAt: provenance.capturedAt
|
|
44678
|
+
});
|
|
44679
|
+
} catch {
|
|
44680
|
+
}
|
|
44681
|
+
}
|
|
44682
|
+
if (config2.autoCreateClaims && (category === "fact" || category === "decision")) {
|
|
44683
|
+
try {
|
|
44684
|
+
await acquire.acquire({
|
|
44685
|
+
id: `claim-${item.id}`,
|
|
44686
|
+
knowledge: { statement, category },
|
|
44687
|
+
applicability: { area: "project" },
|
|
44688
|
+
evidence: [{
|
|
44689
|
+
id: `ev-${item.id}`,
|
|
44690
|
+
source: provenance.source.conversationId,
|
|
44691
|
+
observedAt: provenance.capturedAt,
|
|
44692
|
+
supports: statement
|
|
44693
|
+
}],
|
|
44694
|
+
epistemicType,
|
|
44695
|
+
provenance: { source: "conversation-capture", detail: `category:${category}` },
|
|
44696
|
+
acquiredAt: provenance.capturedAt,
|
|
44697
|
+
scope: "project"
|
|
44698
|
+
});
|
|
44699
|
+
} catch {
|
|
44700
|
+
}
|
|
44701
|
+
}
|
|
44702
|
+
memorio.dispatch.set("dotmem:capture:item-captured", {
|
|
44703
|
+
detail: { id: item.id, category, statement }
|
|
44704
|
+
});
|
|
44705
|
+
}
|
|
44706
|
+
__name(routeToStorage, "routeToStorage");
|
|
44707
|
+
var CaptureEngine = class {
|
|
44708
|
+
static {
|
|
44709
|
+
__name(this, "CaptureEngine");
|
|
44710
|
+
}
|
|
44711
|
+
config;
|
|
44712
|
+
adapters;
|
|
44713
|
+
sessionContexts = /* @__PURE__ */ new Map();
|
|
44714
|
+
constructor(config2 = {}, adapters) {
|
|
44715
|
+
this.config = { ...DEFAULT_CONFIG, ...config2 };
|
|
44716
|
+
this.adapters = {
|
|
44717
|
+
remember: entries.remember.bind(entries),
|
|
44718
|
+
recall: entries.recall.bind(entries),
|
|
44719
|
+
update: entries.update.bind(entries),
|
|
44720
|
+
addExemplar: addExemplar.bind(null),
|
|
44721
|
+
updateExemplar: updateExemplar.bind(null),
|
|
44722
|
+
addLoop: addLoop.bind(null),
|
|
44723
|
+
closeLoop: closeLoop.bind(null),
|
|
44724
|
+
updatePersonalityAnchor: updatePersonalityAnchor.bind(null),
|
|
44725
|
+
...adapters
|
|
44726
|
+
};
|
|
44727
|
+
}
|
|
44728
|
+
/**
|
|
44729
|
+
* Capture information from a conversation turn.
|
|
44730
|
+
* Processes a single message or turn of conversation.
|
|
44731
|
+
*/
|
|
44732
|
+
async captureTurn(text, options) {
|
|
44733
|
+
const source = {
|
|
44734
|
+
conversationId: options.conversationId,
|
|
44735
|
+
messageIds: options.messageIds ?? [],
|
|
44736
|
+
timestamp: nowIso(),
|
|
44737
|
+
turnIndex: 0
|
|
44738
|
+
};
|
|
44739
|
+
const instructions = detectExplicitInstructions(text, source);
|
|
44740
|
+
const hasDoNotRemember = instructions.some((i2) => i2.type === "do-not-remember");
|
|
44741
|
+
const hasExplicitRemember = instructions.some((i2) => i2.type === "remember");
|
|
44742
|
+
let created = 0, linked = 0, ignored = 0;
|
|
44743
|
+
if (hasDoNotRemember && !hasExplicitRemember) {
|
|
44744
|
+
const item2 = {
|
|
44745
|
+
id: generateId(),
|
|
44746
|
+
category: "temporary_context",
|
|
44747
|
+
statement: text,
|
|
44748
|
+
content: { text },
|
|
44749
|
+
entities: [],
|
|
44750
|
+
relationships: [],
|
|
44751
|
+
provenance: {
|
|
44752
|
+
source,
|
|
44753
|
+
classification: "temporary_context",
|
|
44754
|
+
confidence: "low",
|
|
44755
|
+
epistemicType: "observed",
|
|
44756
|
+
capturedAt: nowIso(),
|
|
44757
|
+
method: "automatic"
|
|
44758
|
+
},
|
|
44759
|
+
confidence: "low",
|
|
44760
|
+
epistemicType: "observed"
|
|
44761
|
+
};
|
|
44762
|
+
await this.storeSessionContext(options.conversationId, [item2], instructions);
|
|
44763
|
+
ignored++;
|
|
44764
|
+
return { items: [item2], instructions, created: 0, linked: 0, ignored: 1, dedupMatches: [] };
|
|
44765
|
+
}
|
|
44766
|
+
const category = classifyCategory(text, instructions);
|
|
44767
|
+
const epistemicType = determineEpistemicType(category, text, instructions);
|
|
44768
|
+
const confidence = determineConfidence(category, epistemicType);
|
|
44769
|
+
const entities = extractEntities(text);
|
|
44770
|
+
const relationships = extractRelationships(text, entities);
|
|
44771
|
+
const provenance = {
|
|
44772
|
+
source,
|
|
44773
|
+
classification: category,
|
|
44774
|
+
confidence,
|
|
44775
|
+
epistemicType,
|
|
44776
|
+
capturedAt: nowIso(),
|
|
44777
|
+
method: hasExplicitRemember ? "explicit" : "automatic"
|
|
44778
|
+
};
|
|
44779
|
+
const item = {
|
|
44780
|
+
id: generateId(),
|
|
44781
|
+
category,
|
|
44782
|
+
statement: text,
|
|
44783
|
+
content: { text },
|
|
44784
|
+
entities,
|
|
44785
|
+
relationships,
|
|
44786
|
+
provenance,
|
|
44787
|
+
confidence,
|
|
44788
|
+
epistemicType
|
|
44789
|
+
};
|
|
44790
|
+
const sessionCtx = this.sessionContexts.get(options.conversationId);
|
|
44791
|
+
const existingItems = sessionCtx ? sessionCtx.items : [];
|
|
44792
|
+
const dedupMatches = await findExistingSimilarItems(
|
|
44793
|
+
text,
|
|
44794
|
+
category,
|
|
44795
|
+
existingItems,
|
|
44796
|
+
this.config.dedupSimilarityThreshold
|
|
44797
|
+
);
|
|
44798
|
+
const memoryMatches = await findExistingMemoryEntries(text, category);
|
|
44799
|
+
const allMatches = [...dedupMatches, ...memoryMatches];
|
|
44800
|
+
let decision = "create";
|
|
44801
|
+
if (allMatches.length > 0) {
|
|
44802
|
+
const exactMatch = allMatches.find((m) => m.matchType === "exact");
|
|
44803
|
+
if (exactMatch) {
|
|
44804
|
+
decision = "link";
|
|
44805
|
+
linked++;
|
|
44806
|
+
} else {
|
|
44807
|
+
decision = "create";
|
|
44808
|
+
created++;
|
|
44809
|
+
}
|
|
44810
|
+
} else {
|
|
44811
|
+
created++;
|
|
44812
|
+
}
|
|
44813
|
+
const finalItem = { ...item };
|
|
44814
|
+
const shouldStore = decision === "create" || decision === "link";
|
|
44815
|
+
if (shouldStore) {
|
|
44816
|
+
await routeToStorage(finalItem, this.adapters, this.config);
|
|
44817
|
+
}
|
|
44818
|
+
await this.storeSessionContext(options.conversationId, [finalItem], instructions);
|
|
44819
|
+
return { items: [finalItem], instructions, created, linked, ignored, dedupMatches: allMatches };
|
|
44820
|
+
}
|
|
44821
|
+
/**
|
|
44822
|
+
* Capture information from a full conversation (array of messages).
|
|
44823
|
+
* Processes each message and returns aggregated results.
|
|
44824
|
+
*/
|
|
44825
|
+
async captureConversation(messages, options) {
|
|
44826
|
+
const allItems = [];
|
|
44827
|
+
const allInstructions = [];
|
|
44828
|
+
let created = 0, updated = 0, linked = 0, ignored = 0;
|
|
44829
|
+
const allDedupMatches = [];
|
|
44830
|
+
for (const [index, msg] of messages.entries()) {
|
|
44831
|
+
const source = {
|
|
44832
|
+
conversationId: options.conversationId,
|
|
44833
|
+
messageIds: [msg.id ?? `msg-${index}`],
|
|
44834
|
+
timestamp: msg.timestamp ?? nowIso(),
|
|
44835
|
+
turnIndex: index
|
|
44836
|
+
};
|
|
44837
|
+
const instructions = detectExplicitInstructions(msg.content, source);
|
|
44838
|
+
allInstructions.push(...instructions);
|
|
44839
|
+
const hasDoNotRemember = instructions.some((i2) => i2.type === "do-not-remember");
|
|
44840
|
+
const hasExplicitRemember = instructions.some((i2) => i2.type === "remember");
|
|
44841
|
+
if (hasDoNotRemember && !hasExplicitRemember) {
|
|
44842
|
+
const item2 = {
|
|
44843
|
+
id: generateId(),
|
|
44844
|
+
category: "temporary_context",
|
|
44845
|
+
statement: msg.content,
|
|
44846
|
+
content: { text: msg.content, role: msg.role },
|
|
44847
|
+
entities: [],
|
|
44848
|
+
relationships: [],
|
|
44849
|
+
provenance: {
|
|
44850
|
+
source,
|
|
44851
|
+
classification: "temporary_context",
|
|
44852
|
+
confidence: "low",
|
|
44853
|
+
epistemicType: "observed",
|
|
44854
|
+
capturedAt: nowIso(),
|
|
44855
|
+
method: "automatic"
|
|
44856
|
+
},
|
|
44857
|
+
confidence: "low",
|
|
44858
|
+
epistemicType: "observed"
|
|
44859
|
+
};
|
|
44860
|
+
allItems.push(item2);
|
|
44861
|
+
ignored++;
|
|
44862
|
+
continue;
|
|
44863
|
+
}
|
|
44864
|
+
const category = classifyCategory(msg.content, instructions);
|
|
44865
|
+
const epistemicType = determineEpistemicType(category, msg.content, instructions);
|
|
44866
|
+
const confidence = determineConfidence(category, epistemicType, msg.content);
|
|
44867
|
+
const entities = extractEntities(msg.content);
|
|
44868
|
+
const relationships = extractRelationships(msg.content, entities);
|
|
44869
|
+
const provenance = {
|
|
44870
|
+
source,
|
|
44871
|
+
classification: category,
|
|
44872
|
+
confidence,
|
|
44873
|
+
epistemicType,
|
|
44874
|
+
capturedAt: nowIso(),
|
|
44875
|
+
method: hasExplicitRemember ? "explicit" : "automatic"
|
|
44876
|
+
};
|
|
44877
|
+
const item = {
|
|
44878
|
+
id: generateId(),
|
|
44879
|
+
category,
|
|
44880
|
+
statement: msg.content,
|
|
44881
|
+
content: { text: msg.content, role: msg.role },
|
|
44882
|
+
entities,
|
|
44883
|
+
relationships,
|
|
44884
|
+
provenance,
|
|
44885
|
+
confidence,
|
|
44886
|
+
epistemicType
|
|
44887
|
+
};
|
|
44888
|
+
const dedupMatches = await findExistingSimilarItems(
|
|
44889
|
+
msg.content,
|
|
44890
|
+
category,
|
|
44891
|
+
allItems,
|
|
44892
|
+
this.config.dedupSimilarityThreshold
|
|
44893
|
+
);
|
|
44894
|
+
const memoryMatches = await findExistingMemoryEntries(msg.content, category);
|
|
44895
|
+
const allMatches = [...dedupMatches, ...memoryMatches];
|
|
44896
|
+
allDedupMatches.push(...allMatches);
|
|
44897
|
+
let decision = "create";
|
|
44898
|
+
if (allMatches.length > 0) {
|
|
44899
|
+
const exactMatch = allMatches.find((m) => m.matchType === "exact");
|
|
44900
|
+
if (exactMatch) {
|
|
44901
|
+
decision = "link";
|
|
44902
|
+
linked++;
|
|
44903
|
+
} else {
|
|
44904
|
+
decision = "create";
|
|
44905
|
+
created++;
|
|
44906
|
+
}
|
|
44907
|
+
} else {
|
|
44908
|
+
created++;
|
|
44909
|
+
}
|
|
44910
|
+
const shouldStore = decision === "create" || decision === "link";
|
|
44911
|
+
if (shouldStore) {
|
|
44912
|
+
await routeToStorage(item, this.adapters, this.config);
|
|
44913
|
+
}
|
|
44914
|
+
if (!shouldStore) ignored++;
|
|
44915
|
+
allItems.push(item);
|
|
44916
|
+
}
|
|
44917
|
+
await this.storeSessionContext(options.conversationId, allItems, allInstructions);
|
|
44918
|
+
return {
|
|
44919
|
+
items: allItems,
|
|
44920
|
+
created,
|
|
44921
|
+
updated,
|
|
44922
|
+
linked,
|
|
44923
|
+
ignored,
|
|
44924
|
+
dedupMatches: allDedupMatches,
|
|
44925
|
+
provenance: allItems.map((i2) => i2.provenance)
|
|
44926
|
+
};
|
|
44927
|
+
}
|
|
44928
|
+
/**
|
|
44929
|
+
* Retrieve captured items for a conversation.
|
|
44930
|
+
*/
|
|
44931
|
+
async getCapturedItems(conversationId) {
|
|
44932
|
+
const ctx = this.sessionContexts.get(conversationId);
|
|
44933
|
+
return ctx ? ctx.items : [];
|
|
44934
|
+
}
|
|
44935
|
+
/**
|
|
44936
|
+
* Get all captured items across all conversations.
|
|
44937
|
+
*/
|
|
44938
|
+
async getAllCapturedItems() {
|
|
44939
|
+
const all = [];
|
|
44940
|
+
for (const ctx of this.sessionContexts.values()) {
|
|
44941
|
+
all.push(...ctx.items);
|
|
44942
|
+
}
|
|
44943
|
+
return all;
|
|
44944
|
+
}
|
|
44945
|
+
/**
|
|
44946
|
+
* Clear session context (for testing / cleanup).
|
|
44947
|
+
*/
|
|
44948
|
+
clearSession(conversationId) {
|
|
44949
|
+
this.sessionContexts.delete(conversationId);
|
|
44950
|
+
}
|
|
44951
|
+
/**
|
|
44952
|
+
* Get capture engine configuration.
|
|
44953
|
+
*/
|
|
44954
|
+
getConfig() {
|
|
44955
|
+
return { ...this.config };
|
|
44956
|
+
}
|
|
44957
|
+
// ---------------------------------------------------------------------------
|
|
44958
|
+
// Private
|
|
44959
|
+
// ---------------------------------------------------------------------------
|
|
44960
|
+
async storeSessionContext(conversationId, items, instructions) {
|
|
44961
|
+
let ctx = this.sessionContexts.get(conversationId);
|
|
44962
|
+
if (!ctx) {
|
|
44963
|
+
ctx = {
|
|
44964
|
+
conversationId,
|
|
44965
|
+
startedAt: nowIso(),
|
|
44966
|
+
items: [],
|
|
44967
|
+
explicitInstructions: []
|
|
44968
|
+
};
|
|
44969
|
+
this.sessionContexts.set(conversationId, ctx);
|
|
44970
|
+
}
|
|
44971
|
+
ctx.items.push(...items);
|
|
44972
|
+
ctx.explicitInstructions.push(...instructions);
|
|
44973
|
+
try {
|
|
44974
|
+
const stateKey = `${CAPTURE_STATE_KEY}:${conversationId}`;
|
|
44975
|
+
const existing = store.get(stateKey);
|
|
44976
|
+
let prior = [];
|
|
44977
|
+
if (existing) {
|
|
44978
|
+
try {
|
|
44979
|
+
prior = JSON.parse(existing);
|
|
44980
|
+
} catch {
|
|
44981
|
+
}
|
|
44982
|
+
}
|
|
44983
|
+
store.set(stateKey, JSON.stringify([...prior, ...items]));
|
|
44984
|
+
} catch {
|
|
44985
|
+
}
|
|
44986
|
+
}
|
|
44987
|
+
};
|
|
44988
|
+
var captureEngine = new CaptureEngine();
|
|
44989
|
+
async function captureConversation(messages, options) {
|
|
44990
|
+
return captureEngine.captureConversation(messages, options);
|
|
44991
|
+
}
|
|
44992
|
+
__name(captureConversation, "captureConversation");
|
|
44993
|
+
async function captureTurn(text, options) {
|
|
44994
|
+
return captureEngine.captureTurn(text, options);
|
|
44995
|
+
}
|
|
44996
|
+
__name(captureTurn, "captureTurn");
|
|
44997
|
+
|
|
43728
44998
|
// core/memory/index.ts
|
|
43729
44999
|
init_detection_events();
|
|
43730
45000
|
init_detection_journal();
|
|
@@ -43912,6 +45182,25 @@ var memory = {
|
|
|
43912
45182
|
async getSeedId() {
|
|
43913
45183
|
return SEED_ID;
|
|
43914
45184
|
}
|
|
45185
|
+
},
|
|
45186
|
+
/** Automatic conversational capture engine (Phase 2 — Workstream B). */
|
|
45187
|
+
capture: {
|
|
45188
|
+
engine: captureEngine,
|
|
45189
|
+
async conversation(messages, options) {
|
|
45190
|
+
return captureConversation(messages, options);
|
|
45191
|
+
},
|
|
45192
|
+
async turn(text, options) {
|
|
45193
|
+
return captureTurn(text, options);
|
|
45194
|
+
},
|
|
45195
|
+
async getItems(conversationId) {
|
|
45196
|
+
return captureEngine.getCapturedItems(conversationId);
|
|
45197
|
+
},
|
|
45198
|
+
async getAllItems() {
|
|
45199
|
+
return captureEngine.getAllCapturedItems();
|
|
45200
|
+
},
|
|
45201
|
+
clearSession(conversationId) {
|
|
45202
|
+
captureEngine.clearSession(conversationId);
|
|
45203
|
+
}
|
|
43915
45204
|
}
|
|
43916
45205
|
};
|
|
43917
45206
|
|