dotmem 0.0.4 → 0.0.7

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.js CHANGED
@@ -1,4 +1,4 @@
1
- import { store, DEV, hlc, dispatch, idb, session, state, temporal } from 'memorio';
1
+ import { store as store$1, DEV, hlc, dispatch, idb, session, state, temporal } from 'memorio';
2
2
  import process2 from 'process';
3
3
  import path from 'path';
4
4
  import fs from 'fs';
@@ -64,19 +64,19 @@ var init_journal = __esm({
64
64
  hlc: entry.hlc || hlc.serialize(hlc.tick())
65
65
  };
66
66
  const key = `${STORE_PREFIX(ns)}${row.id}`;
67
- store.set(key, row);
68
- const idx = store.get(INDEX_KEY(ns)) || [];
67
+ store$1.set(key, row);
68
+ const idx = store$1.get(INDEX_KEY(ns)) || [];
69
69
  if (!idx.includes(row.id)) idx.push(row.id);
70
- store.set(INDEX_KEY(ns), idx);
70
+ store$1.set(INDEX_KEY(ns), idx);
71
71
  return row;
72
72
  },
73
73
  /** All pending (not-yet-synced) entries for the current namespace. */
74
74
  async pending() {
75
75
  const ns = namespace();
76
76
  const out = [];
77
- const idx = store.get(INDEX_KEY(ns)) || [];
77
+ const idx = store$1.get(INDEX_KEY(ns)) || [];
78
78
  for (const id of idx) {
79
- const raw = store.get(`${STORE_PREFIX(ns)}${id}`);
79
+ const raw = store$1.get(`${STORE_PREFIX(ns)}${id}`);
80
80
  if (!raw) continue;
81
81
  const e = parseEntry(raw);
82
82
  if (e && e.sync !== "synced") out.push(e);
@@ -99,31 +99,31 @@ var init_journal = __esm({
99
99
  if (!ids.length) return 0;
100
100
  const ns = namespace();
101
101
  let count = 0;
102
- const idx = store.get(INDEX_KEY(ns)) || [];
102
+ const idx = store$1.get(INDEX_KEY(ns)) || [];
103
103
  for (const id of idx) {
104
104
  if (!ids.includes(id)) continue;
105
105
  const key = `${STORE_PREFIX(ns)}${id}`;
106
- const raw = store.get(key);
106
+ const raw = store$1.get(key);
107
107
  if (!raw) continue;
108
108
  const e = parseEntry(raw);
109
109
  if (!e || e.sync === "synced") continue;
110
110
  e.sync = "synced";
111
- store.set(key, e);
111
+ store$1.set(key, e);
112
112
  count++;
113
113
  }
114
114
  return count;
115
115
  },
116
116
  async get(id) {
117
117
  const ns = namespace();
118
- const raw = store.get(`${STORE_PREFIX(ns)}${id}`);
118
+ const raw = store$1.get(`${STORE_PREFIX(ns)}${id}`);
119
119
  return parseEntry(raw ?? "");
120
120
  },
121
121
  /** Remove all journal rows for the current namespace. */
122
122
  async clear() {
123
123
  const ns = namespace();
124
- const idx = store.get(INDEX_KEY(ns)) || [];
125
- for (const id of idx) store.remove(`${STORE_PREFIX(ns)}${id}`);
126
- store.remove(INDEX_KEY(ns));
124
+ const idx = store$1.get(INDEX_KEY(ns)) || [];
125
+ for (const id of idx) store$1.remove(`${STORE_PREFIX(ns)}${id}`);
126
+ store$1.remove(INDEX_KEY(ns));
127
127
  },
128
128
  /**
129
129
  * Reconcile the local journal against the configured provider. Pushes pending
@@ -202,7 +202,7 @@ var init_journal = __esm({
202
202
  */
203
203
  async status() {
204
204
  try {
205
- const capabilities = store.capabilities?.();
205
+ const capabilities = store$1.capabilities?.();
206
206
  return capabilities?.persistent ? "store" : "memory";
207
207
  } catch {
208
208
  return "memory";
@@ -6262,8 +6262,8 @@ var init_user_identity = __esm({
6262
6262
  "core/knowledge/user-identity.ts"() {
6263
6263
  USER_IDENTITY_KEY = "__dotmem_user_identity__";
6264
6264
  identityStore = null;
6265
- configureUserIdentityStore = /* @__PURE__ */ __name((store5) => {
6266
- identityStore = store5;
6265
+ configureUserIdentityStore = /* @__PURE__ */ __name((store6) => {
6266
+ identityStore = store6;
6267
6267
  }, "configureUserIdentityStore");
6268
6268
  requireStore = /* @__PURE__ */ __name(() => {
6269
6269
  if (!identityStore) {
@@ -8688,6 +8688,19 @@ async function readFile6(path3) {
8688
8688
  return null;
8689
8689
  }
8690
8690
  }
8691
+ async function writeFile6(path3, content) {
8692
+ const fs3 = await import('fs/promises');
8693
+ const dir = path3.replace(/[\\/][^\\/]+$/, "");
8694
+ await fs3.mkdir(dir, { recursive: true });
8695
+ const temporary = `${path3}.${process.pid}.${Date.now().toString(36)}.tmp`;
8696
+ try {
8697
+ await fs3.writeFile(temporary, content, "utf8");
8698
+ await fs3.rename(temporary, path3);
8699
+ } catch {
8700
+ await fs3.rm(temporary, { force: true }).catch(() => void 0);
8701
+ throw new Error(`Failed to write exemplars file at ${path3}`);
8702
+ }
8703
+ }
8691
8704
  function emptyStore() {
8692
8705
  return { version: EXEMPLARS_FORMAT_VERSION, exemplars: {} };
8693
8706
  }
@@ -8752,9 +8765,53 @@ async function loadExemplars() {
8752
8765
  return emptyStore();
8753
8766
  }
8754
8767
  }
8768
+ async function saveExemplars(store6) {
8769
+ const validated = validateStore(store6);
8770
+ await writeFile6(resolveExemplarsPath(), JSON.stringify(validated, null, 2));
8771
+ }
8772
+ async function addExemplar(exemplar) {
8773
+ const store6 = await loadExemplars();
8774
+ if (store6.exemplars[exemplar.id]) {
8775
+ throw new Error(`Exemplar ${exemplar.id} already exists`);
8776
+ }
8777
+ if (exemplar.sourceReference) {
8778
+ const existingRef = Object.values(store6.exemplars).find(
8779
+ (e) => e.sourceReference === exemplar.sourceReference
8780
+ );
8781
+ if (existingRef) {
8782
+ throw new Error(`Exemplar with source reference ${exemplar.sourceReference} already exists (id: ${existingRef.id})`);
8783
+ }
8784
+ }
8785
+ const full = {
8786
+ ...exemplar,
8787
+ type: "interaction-exemplar",
8788
+ revision: 1
8789
+ };
8790
+ store6.exemplars[exemplar.id] = full;
8791
+ await saveExemplars(store6);
8792
+ return full;
8793
+ }
8794
+ async function updateExemplar(id, updates) {
8795
+ const store6 = await loadExemplars();
8796
+ const existing = store6.exemplars[id];
8797
+ if (!existing) {
8798
+ throw new Error(`Exemplar ${id} not found`);
8799
+ }
8800
+ const updated = {
8801
+ ...existing,
8802
+ ...updates,
8803
+ id: existing.id,
8804
+ type: "interaction-exemplar",
8805
+ createdAt: existing.createdAt,
8806
+ revision: (updates.revision ?? existing.revision) + 1
8807
+ };
8808
+ store6.exemplars[id] = updated;
8809
+ await saveExemplars(store6);
8810
+ return updated;
8811
+ }
8755
8812
  async function searchExemplars(options = {}) {
8756
- const store5 = await loadExemplars();
8757
- const all = Object.values(store5.exemplars);
8813
+ const store6 = await loadExemplars();
8814
+ const all = Object.values(store6.exemplars);
8758
8815
  const filtered = all.filter((exemplar) => {
8759
8816
  if (options.minSignificance !== void 0 && exemplar.significance < options.minSignificance) {
8760
8817
  return false;
@@ -8814,10 +8871,14 @@ var init_exemplars = __esm({
8814
8871
  __name(joinPath9, "joinPath");
8815
8872
  __name(resolveExemplarsPath, "resolveExemplarsPath");
8816
8873
  __name(readFile6, "readFile");
8874
+ __name(writeFile6, "writeFile");
8817
8875
  __name(emptyStore, "emptyStore");
8818
8876
  __name(validateExemplar, "validateExemplar");
8819
8877
  __name(validateStore, "validateStore");
8820
8878
  __name(loadExemplars, "loadExemplars");
8879
+ __name(saveExemplars, "saveExemplars");
8880
+ __name(addExemplar, "addExemplar");
8881
+ __name(updateExemplar, "updateExemplar");
8821
8882
  __name(searchExemplars, "searchExemplars");
8822
8883
  __name(projectExemplar, "projectExemplar");
8823
8884
  __name(projectExemplarContext, "projectExemplarContext");
@@ -8840,6 +8901,19 @@ async function readFile7(path3) {
8840
8901
  return null;
8841
8902
  }
8842
8903
  }
8904
+ async function writeFile7(path3, content) {
8905
+ const fs3 = await import('fs/promises');
8906
+ const dir = path3.replace(/[\\/][^\\/]+$/, "");
8907
+ await fs3.mkdir(dir, { recursive: true });
8908
+ const temporary = `${path3}.${process.pid}.${Date.now().toString(36)}.tmp`;
8909
+ try {
8910
+ await fs3.writeFile(temporary, content, "utf8");
8911
+ await fs3.rename(temporary, path3);
8912
+ } catch {
8913
+ await fs3.rm(temporary, { force: true }).catch(() => void 0);
8914
+ throw new Error(`Failed to write personality anchor at ${path3}`);
8915
+ }
8916
+ }
8843
8917
  function emptyAnchor() {
8844
8918
  const epoch = "1970-01-01T00:00:00.000Z";
8845
8919
  return {
@@ -8972,6 +9046,33 @@ async function loadPersonalityAnchor() {
8972
9046
  return emptyAnchor();
8973
9047
  }
8974
9048
  }
9049
+ async function savePersonalityAnchor(anchor) {
9050
+ const validated = validateAnchor(anchor);
9051
+ const dirPath = resolveUserDotMemPath();
9052
+ const fs3 = await import('fs/promises');
9053
+ await fs3.mkdir(dirPath, { recursive: true });
9054
+ await writeFile7(resolvePersonalityAnchorPath(), JSON.stringify(validated, null, 2));
9055
+ }
9056
+ async function updatePersonalityAnchor(updates) {
9057
+ const existing = await loadPersonalityAnchor();
9058
+ const now2 = (/* @__PURE__ */ new Date()).toISOString();
9059
+ const updated = {
9060
+ ...existing,
9061
+ identity: {
9062
+ communicationStyle: updates.communicationStyle ?? existing.identity.communicationStyle,
9063
+ durablePreferences: updates.durablePreferences ?? existing.identity.durablePreferences,
9064
+ interactionBoundaries: updates.interactionBoundaries ?? existing.identity.interactionBoundaries
9065
+ },
9066
+ metadata: {
9067
+ ...existing.metadata,
9068
+ updatedAt: now2,
9069
+ revision: existing.metadata.revision + 1,
9070
+ sourceReferences: updates.sourceReferences ? [.../* @__PURE__ */ new Set([...existing.metadata.sourceReferences, ...updates.sourceReferences])] : existing.metadata.sourceReferences
9071
+ }
9072
+ };
9073
+ await savePersonalityAnchor(updated);
9074
+ return updated;
9075
+ }
8975
9076
  function projectPersonalityAnchor(anchor, options) {
8976
9077
  const maxChars = options?.maxCharacters ?? 4e3;
8977
9078
  const hasContent = anchor.identity.communicationStyle.length > 0 || anchor.identity.durablePreferences.length > 0 || anchor.identity.interactionBoundaries.length > 0;
@@ -9026,12 +9127,15 @@ var init_personality_anchor = __esm({
9026
9127
  __name(joinPath10, "joinPath");
9027
9128
  __name(resolvePersonalityAnchorPath, "resolvePersonalityAnchorPath");
9028
9129
  __name(readFile7, "readFile");
9130
+ __name(writeFile7, "writeFile");
9029
9131
  __name(emptyAnchor, "emptyAnchor");
9030
9132
  __name(validateCommunicationStyle, "validateCommunicationStyle");
9031
9133
  __name(validateDurablePreference, "validateDurablePreference");
9032
9134
  __name(validateInteractionBoundary, "validateInteractionBoundary");
9033
9135
  __name(validateAnchor, "validateAnchor");
9034
9136
  __name(loadPersonalityAnchor, "loadPersonalityAnchor");
9137
+ __name(savePersonalityAnchor, "savePersonalityAnchor");
9138
+ __name(updatePersonalityAnchor, "updatePersonalityAnchor");
9035
9139
  __name(projectPersonalityAnchor, "projectPersonalityAnchor");
9036
9140
  __name(calculateAnchorBudget, "calculateAnchorBudget");
9037
9141
  }
@@ -9567,7 +9671,7 @@ var init_knowledge_runtime = __esm({
9567
9671
  __name(this, "StoreKnowledgeRepository");
9568
9672
  }
9569
9673
  async load() {
9570
- const raw = store.get(KNOWLEDGE_STATE_KEY);
9674
+ const raw = store$1.get(KNOWLEDGE_STATE_KEY);
9571
9675
  if (!raw) return { version: 0, claims: [] };
9572
9676
  return typeof raw === "string" ? JSON.parse(raw) : raw;
9573
9677
  }
@@ -9577,7 +9681,7 @@ var init_knowledge_runtime = __esm({
9577
9681
  if (current.version !== expectedVersion) {
9578
9682
  throw new Error(`Stale update: expected persisted version ${expectedVersion}, received ${current.version}`);
9579
9683
  }
9580
- store.set(KNOWLEDGE_STATE_KEY, state2);
9684
+ store$1.set(KNOWLEDGE_STATE_KEY, state2);
9581
9685
  }, "write");
9582
9686
  const previous = knowledgeSaveQueue;
9583
9687
  knowledgeSaveQueue = previous.then(write, write);
@@ -9723,27 +9827,27 @@ var init_policy2 = __esm({
9723
9827
  }
9724
9828
  }, "auditPolicyAction");
9725
9829
  resolveOverrides = /* @__PURE__ */ __name(async (namespace2, now2 = () => /* @__PURE__ */ new Date()) => {
9726
- const store5 = await getPolicyStore();
9830
+ const store6 = await getPolicyStore();
9727
9831
  const namespaces = namespace2 ? [namespace2] : POLICY_NAMESPACES;
9728
- const documents = await Promise.all(namespaces.map((entry) => store5.load(entry)));
9832
+ const documents = await Promise.all(namespaces.map((entry) => store6.load(entry)));
9729
9833
  return documents.flatMap((document) => document.overrides.map(
9730
9834
  (override) => resolveOverrideState(override, document.records.find((record) => record.id === override.targetPolicyId), now2)
9731
9835
  )).sort((left, right) => left.override.id.localeCompare(right.override.id));
9732
9836
  }, "resolveOverrides");
9733
9837
  policy = {
9734
9838
  async assign(input, namespace2 = "operator", basedOnRevision) {
9735
- const store5 = await getPolicyStore();
9736
- const record = await store5.assign(input, namespace2, basedOnRevision);
9839
+ const store6 = await getPolicyStore();
9840
+ const record = await store6.assign(input, namespace2, basedOnRevision);
9737
9841
  auditPolicyAction("policy.assign", record.id);
9738
9842
  return record;
9739
9843
  },
9740
9844
  async list() {
9741
- const store5 = await getPolicyStore();
9742
- return store5.list();
9845
+ const store6 = await getPolicyStore();
9846
+ return store6.list();
9743
9847
  },
9744
9848
  async remove(id, namespace2 = "operator", basedOnRevision) {
9745
- const store5 = await getPolicyStore();
9746
- await store5.remove(id, namespace2, basedOnRevision);
9849
+ const store6 = await getPolicyStore();
9850
+ await store6.remove(id, namespace2, basedOnRevision);
9747
9851
  auditPolicyAction("policy.remove", id);
9748
9852
  },
9749
9853
  /**
@@ -9757,16 +9861,16 @@ var init_policy2 = __esm({
9757
9861
  * the durable audit trail with a terminal CLEAR entry.
9758
9862
  */
9759
9863
  async clear(authority) {
9760
- const store5 = await getPolicyStore();
9761
- await store5.clear(authority);
9864
+ const store6 = await getPolicyStore();
9865
+ await store6.clear(authority);
9762
9866
  auditPolicyAction("policy.clear", "policy");
9763
9867
  },
9764
9868
  async evaluate(event, payload) {
9765
- const store5 = await getPolicyStore();
9869
+ const store6 = await getPolicyStore();
9766
9870
  const [state2, policies, overrides] = await Promise.all([
9767
9871
  loadCombinedKnowledgeState(),
9768
- store5.list(),
9769
- store5.listOverrides()
9872
+ store6.list(),
9873
+ store6.listOverrides()
9770
9874
  ]);
9771
9875
  const claims = activeClaims(state2);
9772
9876
  return evaluatePolicies({ event, claims, policies, overrides, payload });
@@ -9788,14 +9892,14 @@ var init_policy2 = __esm({
9788
9892
  */
9789
9893
  override: {
9790
9894
  async grant(input, namespace2 = "operator", basedOnRevision) {
9791
- const store5 = await getPolicyStore();
9792
- const override = await store5.grantOverride(input, namespace2, basedOnRevision);
9895
+ const store6 = await getPolicyStore();
9896
+ const override = await store6.grantOverride(input, namespace2, basedOnRevision);
9793
9897
  auditPolicyAction("policy.override", override.id);
9794
9898
  return override;
9795
9899
  },
9796
9900
  async revoke(input, namespace2 = "operator", basedOnRevision) {
9797
- const store5 = await getPolicyStore();
9798
- const override = await store5.revokeOverride(input, namespace2, basedOnRevision);
9901
+ const store6 = await getPolicyStore();
9902
+ const override = await store6.revokeOverride(input, namespace2, basedOnRevision);
9799
9903
  auditPolicyAction("policy.revoke", override.id);
9800
9904
  return override;
9801
9905
  },
@@ -9803,8 +9907,8 @@ var init_policy2 = __esm({
9803
9907
  return resolveOverrides(namespace2);
9804
9908
  },
9805
9909
  async effective(event, namespace2) {
9806
- const store5 = await getPolicyStore();
9807
- const states = await store5.effectiveState(namespace2);
9910
+ const store6 = await getPolicyStore();
9911
+ const states = await store6.effectiveState(namespace2);
9808
9912
  if (event === void 0) return states;
9809
9913
  const canonical = event.trim();
9810
9914
  return states.filter((state2) => state2.event === canonical);
@@ -9817,8 +9921,8 @@ var init_policy2 = __esm({
9817
9921
  * additional best-effort sink, and this is the durable record.
9818
9922
  */
9819
9923
  async audit(namespace2) {
9820
- const store5 = await getPolicyStore();
9821
- return store5.auditTrail(namespace2);
9924
+ const store6 = await getPolicyStore();
9925
+ return store6.auditTrail(namespace2);
9822
9926
  },
9823
9927
  contract() {
9824
9928
  return MEMORY_PROJECTION_CONTRACT;
@@ -9951,7 +10055,7 @@ async function saveToScope(entry) {
9951
10055
  session.set(storageKey, serialized);
9952
10056
  break;
9953
10057
  case "local":
9954
- store.set(storageKey, serialized);
10058
+ store$1.set(storageKey, serialized);
9955
10059
  break;
9956
10060
  case "durable":
9957
10061
  await idb.set("memories", storageKey, serialized);
@@ -9972,7 +10076,7 @@ async function loadFromScope(id, scope, isSuperseded = false) {
9972
10076
  raw = session.get(storageKey);
9973
10077
  break;
9974
10078
  case "local":
9975
- raw = store.get(storageKey);
10079
+ raw = store$1.get(storageKey);
9976
10080
  break;
9977
10081
  case "durable":
9978
10082
  raw = await idb.get("memories", storageKey);
@@ -10014,7 +10118,7 @@ async function removeFromScope(id, scope, isSuperseded = false) {
10014
10118
  session.remove(storageKey);
10015
10119
  break;
10016
10120
  case "local":
10017
- store.remove(storageKey);
10121
+ store$1.remove(storageKey);
10018
10122
  break;
10019
10123
  case "durable":
10020
10124
  await idb.deleteKey("memories", storageKey);
@@ -10024,7 +10128,7 @@ async function removeFromScope(id, scope, isSuperseded = false) {
10024
10128
  }
10025
10129
  async function getAllIndexes() {
10026
10130
  try {
10027
- const raw = store.get(MEMORY_INDEX_KEY);
10131
+ const raw = store$1.get(MEMORY_INDEX_KEY);
10028
10132
  if (!raw) return {};
10029
10133
  return JSON.parse(raw);
10030
10134
  } catch (err2) {
@@ -10035,7 +10139,7 @@ async function getAllIndexes() {
10035
10139
  async function updateIndex(id, scope, isSuperseded = false) {
10036
10140
  const index = await getAllIndexes();
10037
10141
  index[id] = { scope, superseded: isSuperseded };
10038
- store.set(MEMORY_INDEX_KEY, JSON.stringify(index));
10142
+ store$1.set(MEMORY_INDEX_KEY, JSON.stringify(index));
10039
10143
  }
10040
10144
  async function removeFromIndex(id, isSuperseded = false) {
10041
10145
  const index = await getAllIndexes();
@@ -10047,7 +10151,7 @@ async function removeFromIndex(id, isSuperseded = false) {
10047
10151
  delete index[id];
10048
10152
  }
10049
10153
  }
10050
- store.set(MEMORY_INDEX_KEY, JSON.stringify(index));
10154
+ store$1.set(MEMORY_INDEX_KEY, JSON.stringify(index));
10051
10155
  }
10052
10156
  async function loadAll() {
10053
10157
  const index = await getAllIndexes();
@@ -10288,7 +10392,7 @@ var init_entries = __esm({
10288
10392
  for (const [id, info] of Object.entries(index)) {
10289
10393
  await removeFromScope(id, info.scope, info.superseded);
10290
10394
  }
10291
- store.remove(MEMORY_INDEX_KEY);
10395
+ store$1.remove(MEMORY_INDEX_KEY);
10292
10396
  },
10293
10397
  async _getEntry(key) {
10294
10398
  return getEntry(key);
@@ -11232,6 +11336,783 @@ var init_seed = __esm({
11232
11336
  }, "injectJoySeed");
11233
11337
  }
11234
11338
  });
11339
+ function generateId() {
11340
+ return `capture-${hlc.serialize(hlc.tick())}-${Math.random().toString(36).slice(2, 10)}`;
11341
+ }
11342
+ function nowIso() {
11343
+ return (/* @__PURE__ */ new Date()).toISOString();
11344
+ }
11345
+ function normalizeText(text) {
11346
+ return text.normalize("NFKC").toLocaleLowerCase("en-US").replace(/[^\w\s]/g, " ").replace(/\s+/g, " ").trim();
11347
+ }
11348
+ function tokenize(text) {
11349
+ return new Set(normalizeText(text).split(" ").filter((t) => t.length > 2));
11350
+ }
11351
+ function jaccardSimilarity(a, b) {
11352
+ const ta = tokenize(a);
11353
+ const tb = tokenize(b);
11354
+ if (ta.size === 0 && tb.size === 0) return 1;
11355
+ if (ta.size === 0 || tb.size === 0) return 0;
11356
+ const intersection = new Set([...ta].filter((x2) => tb.has(x2)));
11357
+ const union = /* @__PURE__ */ new Set([...ta, ...tb]);
11358
+ return intersection.size / union.size;
11359
+ }
11360
+ function containsPhrase2(text, phrase) {
11361
+ const t = normalizeText(text);
11362
+ const p = normalizeText(phrase);
11363
+ return t.includes(p);
11364
+ }
11365
+ function detectExplicitInstructions(text, source) {
11366
+ const instructions = [];
11367
+ for (const pattern of REMEMBER_PATTERNS) {
11368
+ if (pattern.test(text)) {
11369
+ instructions.push({
11370
+ type: "remember",
11371
+ content: text,
11372
+ source,
11373
+ timestamp: nowIso()
11374
+ });
11375
+ break;
11376
+ }
11377
+ }
11378
+ for (const pattern of DO_NOT_REMEMBER_PATTERNS) {
11379
+ if (pattern.test(text)) {
11380
+ instructions.push({
11381
+ type: "do-not-remember",
11382
+ content: text,
11383
+ source,
11384
+ timestamp: nowIso()
11385
+ });
11386
+ break;
11387
+ }
11388
+ }
11389
+ return instructions;
11390
+ }
11391
+ function classifyCategory(text, explicitInstructions) {
11392
+ const lower = text.toLocaleLowerCase("en-US");
11393
+ if (explicitInstructions.some((i2) => i2.type === "do-not-remember")) {
11394
+ return "temporary_context";
11395
+ }
11396
+ if (explicitInstructions.some((i2) => i2.type === "remember")) {
11397
+ if (/prefer|prefers|like|likes|favorite|always|never/i.test(lower)) {
11398
+ return "preference";
11399
+ }
11400
+ if (/decided|decision|agreed|chose|adopt/i.test(lower)) {
11401
+ return "decision";
11402
+ }
11403
+ return "fact";
11404
+ }
11405
+ const scores = {};
11406
+ for (const cat of Object.keys(CATEGORY_KEYWORDS)) {
11407
+ scores[cat] = CATEGORY_KEYWORDS[cat].filter((kw) => containsPhrase2(lower, kw)).length;
11408
+ }
11409
+ if (/probably|likely|maybe|perhaps|seems|appears|might|could be/i.test(lower)) {
11410
+ scores.inference += 3;
11411
+ }
11412
+ if (text.includes("?")) {
11413
+ scores.question += 3;
11414
+ }
11415
+ if (/decided|decision|agreed|chose|adopt|will use|going with|resolve|settled/i.test(lower)) {
11416
+ scores.decision += 3;
11417
+ }
11418
+ if (/prefer|prefers|like|likes|favorite|always|never|don.t like|dislike/i.test(lower)) {
11419
+ scores.preference += 3;
11420
+ }
11421
+ if (/still need to|pending|waiting for|todo|to do|unresolved|outstanding|follow.?up|blocked/i.test(lower)) {
11422
+ scores.open_loop += 3;
11423
+ }
11424
+ if (/remember when|we talked about|discussed|experienced|encountered|session|conversation/i.test(lower)) {
11425
+ scores.experience += 2;
11426
+ }
11427
+ if (/repository|architecture|deploy|ci|pipeline/i.test(lower)) {
11428
+ scores.project_context += 2;
11429
+ }
11430
+ if (/just for|this session|for now|temporary/i.test(lower)) {
11431
+ scores.temporary_context += 3;
11432
+ }
11433
+ if (scores.fact > 0 && scores.project_context > 0 && scores.fact === scores.project_context) {
11434
+ scores.fact += 1;
11435
+ }
11436
+ let bestCategory = "fact";
11437
+ let bestScore = -1;
11438
+ for (const [cat, score] of Object.entries(scores)) {
11439
+ if (score > bestScore) {
11440
+ bestScore = score;
11441
+ bestCategory = cat;
11442
+ }
11443
+ }
11444
+ if (bestScore === 0) return "fact";
11445
+ return bestCategory;
11446
+ }
11447
+ function determineEpistemicType(category, text, explicitInstructions) {
11448
+ if (explicitInstructions.some((i2) => i2.type === "remember")) {
11449
+ return "human-stated";
11450
+ }
11451
+ if (category === "inference" || /probably|likely|maybe|perhaps|seems|appears/i.test(text)) {
11452
+ return "inferred";
11453
+ }
11454
+ if (category === "question") return "observed";
11455
+ return "observed";
11456
+ }
11457
+ function determineConfidence(category, epistemicType, _text) {
11458
+ if (epistemicType === "human-stated") return "high";
11459
+ if (epistemicType === "inferred") return "low";
11460
+ if (category === "decision" || category === "preference") return "medium";
11461
+ if (category === "question") return "medium";
11462
+ if (category === "fact") return "medium";
11463
+ return "low";
11464
+ }
11465
+ function extractEntities(text) {
11466
+ const entities = [];
11467
+ const seen = /* @__PURE__ */ new Set();
11468
+ const capitalizedMatches = text.match(/\b[A-Z][a-zA-Z]+(?:\s+[A-Z][a-zA-Z]+)*\b/g) || [];
11469
+ for (const match of capitalizedMatches) {
11470
+ if (seen.has(match)) continue;
11471
+ seen.add(match);
11472
+ entities.push({
11473
+ id: `entity-${normalizeText(match)}`,
11474
+ type: "concept",
11475
+ name: match,
11476
+ aliases: [],
11477
+ relationships: []
11478
+ });
11479
+ }
11480
+ const quotedMatches = text.match(/["'`]([^"`']{2,})["'`]/g) || [];
11481
+ for (const match of quotedMatches) {
11482
+ const clean = match.replace(/["'`]/g, "");
11483
+ if (seen.has(clean)) continue;
11484
+ seen.add(clean);
11485
+ entities.push({
11486
+ id: `entity-${normalizeText(clean)}`,
11487
+ type: "concept",
11488
+ name: clean,
11489
+ aliases: [],
11490
+ relationships: []
11491
+ });
11492
+ }
11493
+ return entities;
11494
+ }
11495
+ function extractRelationships(_text, entities) {
11496
+ const relationships = [];
11497
+ if (entities.length < 2) return relationships;
11498
+ for (let i2 = 0; i2 < entities.length - 1; i2++) {
11499
+ for (let j = i2 + 1; j < entities.length; j++) {
11500
+ relationships.push({
11501
+ from: entities[i2].id,
11502
+ to: entities[j].id,
11503
+ type: "related-to",
11504
+ confidence: 0.5
11505
+ });
11506
+ }
11507
+ }
11508
+ return relationships;
11509
+ }
11510
+ async function findExistingSimilarItems(statement, category, existingItems, threshold) {
11511
+ const matches2 = [];
11512
+ for (const existing of existingItems) {
11513
+ if (existing.category !== category) continue;
11514
+ const similarity = jaccardSimilarity(statement, existing.statement);
11515
+ if (similarity >= threshold) {
11516
+ matches2.push({
11517
+ existingId: existing.id,
11518
+ existingStatement: existing.statement,
11519
+ similarity,
11520
+ matchType: similarity >= 0.95 ? "exact" : "semantic",
11521
+ category: existing.category
11522
+ });
11523
+ }
11524
+ }
11525
+ return matches2;
11526
+ }
11527
+ async function findExistingMemoryEntries(statement, category) {
11528
+ const matches2 = [];
11529
+ try {
11530
+ const all = await entries._loadAll();
11531
+ for (const entry of all) {
11532
+ if (entry.status !== "active") continue;
11533
+ if (entry.type !== category && entry.type !== "fact") continue;
11534
+ const entryText = typeof entry.value === "string" ? entry.value : JSON.stringify(entry.value);
11535
+ const similarity = jaccardSimilarity(statement, entryText);
11536
+ if (similarity >= DEFAULT_CONFIG.dedupSimilarityThreshold) {
11537
+ matches2.push({
11538
+ existingId: entry.id,
11539
+ existingStatement: entryText,
11540
+ similarity,
11541
+ matchType: similarity >= 0.95 ? "exact" : "semantic",
11542
+ category
11543
+ });
11544
+ }
11545
+ }
11546
+ } catch {
11547
+ }
11548
+ return matches2;
11549
+ }
11550
+ function shouldStoreInCoreMemory(category, epistemicType) {
11551
+ return category === "preference" && epistemicType === "human-stated";
11552
+ }
11553
+ async function routeToStorage(item, adapters, config) {
11554
+ const { category, epistemicType, statement, entities, provenance, confidence } = item;
11555
+ const memKey = `capture:${item.id}`;
11556
+ await entries.remember(memKey, {
11557
+ id: item.id,
11558
+ category,
11559
+ statement,
11560
+ entities,
11561
+ relationships: item.relationships,
11562
+ provenance,
11563
+ confidence,
11564
+ epistemicType,
11565
+ capturedAt: provenance.capturedAt
11566
+ }, {
11567
+ id: item.id,
11568
+ type: category === "preference" ? "preference" : category === "decision" ? "decision" : category === "fact" ? "fact" : "context",
11569
+ confidence: confidence === "high" ? 1 : confidence === "medium" ? 0.7 : 0.4,
11570
+ scope: category === "temporary_context" ? "session" : "local",
11571
+ tags: [category, provenance.epistemicType, provenance.source.conversationId],
11572
+ source: `capture:${provenance.source.conversationId}`
11573
+ });
11574
+ if (shouldStoreInCoreMemory(category, epistemicType)) {
11575
+ try {
11576
+ const anchor = await loadPersonalityAnchor();
11577
+ const existingPref = anchor.identity.durablePreferences.find((p) => p.statement === statement);
11578
+ if (!existingPref) {
11579
+ await updatePersonalityAnchor({
11580
+ durablePreferences: [
11581
+ ...anchor.identity.durablePreferences,
11582
+ {
11583
+ id: item.id,
11584
+ statement,
11585
+ confidence: epistemicType,
11586
+ evidence: [provenance.source.conversationId],
11587
+ firstObserved: provenance.capturedAt,
11588
+ lastConfirmed: provenance.capturedAt
11589
+ }
11590
+ ]
11591
+ });
11592
+ }
11593
+ } catch {
11594
+ }
11595
+ }
11596
+ if (category === "open_loop" && config.autoCreateLoops) {
11597
+ try {
11598
+ const existingLoops = await listLoops(true);
11599
+ const alreadyExists = existingLoops.some((l) => l.text === statement);
11600
+ if (!alreadyExists) {
11601
+ await addLoop({
11602
+ id: item.id,
11603
+ text: statement,
11604
+ waitor: "joy",
11605
+ openedAt: provenance.capturedAt
11606
+ });
11607
+ }
11608
+ } catch {
11609
+ }
11610
+ }
11611
+ if (category === "experience" && config.autoCreateExemplars) {
11612
+ try {
11613
+ await addExemplar({
11614
+ id: item.id,
11615
+ source: {
11616
+ conversationId: provenance.source.conversationId,
11617
+ messageIds: provenance.source.messageIds
11618
+ },
11619
+ pattern: statement,
11620
+ originalContent: statement,
11621
+ sourceReference: `capture:${item.id}`,
11622
+ retrievalHints: [statement, ...entities.map((e) => e.name)],
11623
+ significance: confidence === "high" ? 0.8 : confidence === "medium" ? 0.5 : 0.3,
11624
+ confidence: confidence === "high" ? 1 : confidence === "medium" ? 0.7 : 0.4,
11625
+ provenance: epistemicType,
11626
+ createdAt: provenance.capturedAt
11627
+ });
11628
+ } catch {
11629
+ }
11630
+ }
11631
+ if (config.autoCreateClaims && (category === "fact" || category === "decision")) {
11632
+ try {
11633
+ await acquire.acquire({
11634
+ id: `claim-${item.id}`,
11635
+ knowledge: { statement, category },
11636
+ applicability: { area: "project" },
11637
+ evidence: [{
11638
+ id: `ev-${item.id}`,
11639
+ source: provenance.source.conversationId,
11640
+ observedAt: provenance.capturedAt,
11641
+ supports: statement
11642
+ }],
11643
+ epistemicType,
11644
+ provenance: { source: "conversation-capture", detail: `category:${category}` },
11645
+ acquiredAt: provenance.capturedAt,
11646
+ scope: "project"
11647
+ });
11648
+ } catch {
11649
+ }
11650
+ }
11651
+ dispatch.set("dotmem:capture:item-captured", {
11652
+ detail: { id: item.id, category, statement }
11653
+ });
11654
+ }
11655
+ async function captureConversation(messages, options) {
11656
+ return captureEngine.captureConversation(messages, options);
11657
+ }
11658
+ async function captureTurn(text, options) {
11659
+ return captureEngine.captureTurn(text, options);
11660
+ }
11661
+ var CAPTURE_STATE_KEY, DEFAULT_CONFIG, CATEGORY_KEYWORDS, REMEMBER_PATTERNS, DO_NOT_REMEMBER_PATTERNS, CaptureEngine, captureEngine;
11662
+ var init_capture_engine = __esm({
11663
+ "core/memory/capture-engine.ts"() {
11664
+ init_exemplars();
11665
+ init_loops();
11666
+ init_personality_anchor();
11667
+ init_entries();
11668
+ init_acquire();
11669
+ CAPTURE_STATE_KEY = "__dotmem_capture_state__";
11670
+ DEFAULT_CONFIG = {
11671
+ minSignificance: 0.3,
11672
+ maxItemsPerConversation: 50,
11673
+ dedupSimilarityThreshold: 0.75,
11674
+ preserveConflicts: true,
11675
+ tempContextTtlMs: 24 * 60 * 60 * 1e3,
11676
+ autoCreateExemplars: true,
11677
+ autoCreateLoops: true,
11678
+ autoCreateClaims: true
11679
+ };
11680
+ CATEGORY_KEYWORDS = {
11681
+ fact: [
11682
+ "is",
11683
+ "are",
11684
+ "was",
11685
+ "were",
11686
+ "uses",
11687
+ "built with",
11688
+ "depends on",
11689
+ "located at",
11690
+ "named",
11691
+ "called",
11692
+ "version",
11693
+ "language",
11694
+ "framework",
11695
+ "test",
11696
+ "testing"
11697
+ ],
11698
+ decision: [
11699
+ "decided",
11700
+ "decision",
11701
+ "agreed",
11702
+ "chose",
11703
+ "selected",
11704
+ "adopt",
11705
+ "going with",
11706
+ "will use",
11707
+ "commit to",
11708
+ "resolve",
11709
+ "settled"
11710
+ ],
11711
+ experience: [
11712
+ "remember when",
11713
+ "we talked about",
11714
+ "discussed",
11715
+ "experienced",
11716
+ "encountered",
11717
+ "faced",
11718
+ "went through",
11719
+ "session",
11720
+ "conversation"
11721
+ ],
11722
+ question: [
11723
+ "?",
11724
+ "how do",
11725
+ "what is",
11726
+ "why",
11727
+ "when",
11728
+ "where",
11729
+ "which",
11730
+ "can you",
11731
+ "should we",
11732
+ "is it possible"
11733
+ ],
11734
+ open_loop: [
11735
+ "still need to",
11736
+ "pending",
11737
+ "waiting for",
11738
+ "todo",
11739
+ "to do",
11740
+ "open",
11741
+ "unresolved",
11742
+ "outstanding",
11743
+ "follow up",
11744
+ "blocked"
11745
+ ],
11746
+ preference: [
11747
+ "prefer",
11748
+ "prefers",
11749
+ "like",
11750
+ "likes",
11751
+ "favorite",
11752
+ "always",
11753
+ "never",
11754
+ "don't like",
11755
+ "dislike",
11756
+ "style",
11757
+ "habit"
11758
+ ],
11759
+ project_context: [
11760
+ "project",
11761
+ "repository",
11762
+ "codebase",
11763
+ "architecture",
11764
+ "stack",
11765
+ "deploy",
11766
+ "ci",
11767
+ "pipeline",
11768
+ "package"
11769
+ ],
11770
+ temporary_context: [
11771
+ "for now",
11772
+ "just for",
11773
+ "temporary",
11774
+ "this session",
11775
+ "currently",
11776
+ "right now",
11777
+ "at the moment",
11778
+ "for this task"
11779
+ ],
11780
+ inference: [
11781
+ "probably",
11782
+ "likely",
11783
+ "maybe",
11784
+ "perhaps",
11785
+ "seems",
11786
+ "appears",
11787
+ "suggests",
11788
+ "indicates",
11789
+ "implies",
11790
+ "might",
11791
+ "could be"
11792
+ ]
11793
+ };
11794
+ REMEMBER_PATTERNS = [
11795
+ /remember this/i,
11796
+ /remember that/i,
11797
+ /keep this in mind/i,
11798
+ /don't forget/i,
11799
+ /do not forget/i,
11800
+ /store this/i,
11801
+ /save this/i
11802
+ ];
11803
+ DO_NOT_REMEMBER_PATTERNS = [
11804
+ /don't remember/i,
11805
+ /do not remember/i,
11806
+ /forget this/i,
11807
+ /don't store/i,
11808
+ /do not store/i,
11809
+ /not relevant/i,
11810
+ /ignore this/i,
11811
+ /temporary only/i,
11812
+ /this session only/i
11813
+ ];
11814
+ __name(generateId, "generateId");
11815
+ __name(nowIso, "nowIso");
11816
+ __name(normalizeText, "normalizeText");
11817
+ __name(tokenize, "tokenize");
11818
+ __name(jaccardSimilarity, "jaccardSimilarity");
11819
+ __name(containsPhrase2, "containsPhrase");
11820
+ __name(detectExplicitInstructions, "detectExplicitInstructions");
11821
+ __name(classifyCategory, "classifyCategory");
11822
+ __name(determineEpistemicType, "determineEpistemicType");
11823
+ __name(determineConfidence, "determineConfidence");
11824
+ __name(extractEntities, "extractEntities");
11825
+ __name(extractRelationships, "extractRelationships");
11826
+ __name(findExistingSimilarItems, "findExistingSimilarItems");
11827
+ __name(findExistingMemoryEntries, "findExistingMemoryEntries");
11828
+ __name(shouldStoreInCoreMemory, "shouldStoreInCoreMemory");
11829
+ __name(routeToStorage, "routeToStorage");
11830
+ CaptureEngine = class {
11831
+ static {
11832
+ __name(this, "CaptureEngine");
11833
+ }
11834
+ config;
11835
+ adapters;
11836
+ sessionContexts = /* @__PURE__ */ new Map();
11837
+ constructor(config = {}, adapters) {
11838
+ this.config = { ...DEFAULT_CONFIG, ...config };
11839
+ this.adapters = {
11840
+ remember: entries.remember.bind(entries),
11841
+ recall: entries.recall.bind(entries),
11842
+ update: entries.update.bind(entries),
11843
+ addExemplar: addExemplar.bind(null),
11844
+ updateExemplar: updateExemplar.bind(null),
11845
+ addLoop: addLoop.bind(null),
11846
+ closeLoop: closeLoop.bind(null),
11847
+ updatePersonalityAnchor: updatePersonalityAnchor.bind(null),
11848
+ ...adapters
11849
+ };
11850
+ }
11851
+ /**
11852
+ * Capture information from a conversation turn.
11853
+ * Processes a single message or turn of conversation.
11854
+ */
11855
+ async captureTurn(text, options) {
11856
+ const source = {
11857
+ conversationId: options.conversationId,
11858
+ messageIds: options.messageIds ?? [],
11859
+ timestamp: nowIso(),
11860
+ turnIndex: 0
11861
+ };
11862
+ const instructions = detectExplicitInstructions(text, source);
11863
+ const hasDoNotRemember = instructions.some((i2) => i2.type === "do-not-remember");
11864
+ const hasExplicitRemember = instructions.some((i2) => i2.type === "remember");
11865
+ let created = 0, linked = 0, ignored = 0;
11866
+ if (hasDoNotRemember && !hasExplicitRemember) {
11867
+ const item2 = {
11868
+ id: generateId(),
11869
+ category: "temporary_context",
11870
+ statement: text,
11871
+ content: { text },
11872
+ entities: [],
11873
+ relationships: [],
11874
+ provenance: {
11875
+ source,
11876
+ classification: "temporary_context",
11877
+ confidence: "low",
11878
+ epistemicType: "observed",
11879
+ capturedAt: nowIso(),
11880
+ method: "automatic"
11881
+ },
11882
+ confidence: "low",
11883
+ epistemicType: "observed"
11884
+ };
11885
+ await this.storeSessionContext(options.conversationId, [item2], instructions);
11886
+ ignored++;
11887
+ return { items: [item2], instructions, created: 0, linked: 0, ignored: 1, dedupMatches: [] };
11888
+ }
11889
+ const category = classifyCategory(text, instructions);
11890
+ const epistemicType = determineEpistemicType(category, text, instructions);
11891
+ const confidence = determineConfidence(category, epistemicType);
11892
+ const entities = extractEntities(text);
11893
+ const relationships = extractRelationships(text, entities);
11894
+ const provenance = {
11895
+ source,
11896
+ classification: category,
11897
+ confidence,
11898
+ epistemicType,
11899
+ capturedAt: nowIso(),
11900
+ method: hasExplicitRemember ? "explicit" : "automatic"
11901
+ };
11902
+ const item = {
11903
+ id: generateId(),
11904
+ category,
11905
+ statement: text,
11906
+ content: { text },
11907
+ entities,
11908
+ relationships,
11909
+ provenance,
11910
+ confidence,
11911
+ epistemicType
11912
+ };
11913
+ const sessionCtx = this.sessionContexts.get(options.conversationId);
11914
+ const existingItems = sessionCtx ? sessionCtx.items : [];
11915
+ const dedupMatches = await findExistingSimilarItems(
11916
+ text,
11917
+ category,
11918
+ existingItems,
11919
+ this.config.dedupSimilarityThreshold
11920
+ );
11921
+ const memoryMatches = await findExistingMemoryEntries(text, category);
11922
+ const allMatches = [...dedupMatches, ...memoryMatches];
11923
+ let decision = "create";
11924
+ if (allMatches.length > 0) {
11925
+ const exactMatch = allMatches.find((m) => m.matchType === "exact");
11926
+ if (exactMatch) {
11927
+ decision = "link";
11928
+ linked++;
11929
+ } else {
11930
+ decision = "create";
11931
+ created++;
11932
+ }
11933
+ } else {
11934
+ created++;
11935
+ }
11936
+ const finalItem = { ...item };
11937
+ const shouldStore = decision === "create" || decision === "link";
11938
+ if (shouldStore) {
11939
+ await routeToStorage(finalItem, this.adapters, this.config);
11940
+ }
11941
+ await this.storeSessionContext(options.conversationId, [finalItem], instructions);
11942
+ return { items: [finalItem], instructions, created, linked, ignored, dedupMatches: allMatches };
11943
+ }
11944
+ /**
11945
+ * Capture information from a full conversation (array of messages).
11946
+ * Processes each message and returns aggregated results.
11947
+ */
11948
+ async captureConversation(messages, options) {
11949
+ const allItems = [];
11950
+ const allInstructions = [];
11951
+ let created = 0, updated = 0, linked = 0, ignored = 0;
11952
+ const allDedupMatches = [];
11953
+ for (const [index, msg] of messages.entries()) {
11954
+ const source = {
11955
+ conversationId: options.conversationId,
11956
+ messageIds: [msg.id ?? `msg-${index}`],
11957
+ timestamp: msg.timestamp ?? nowIso(),
11958
+ turnIndex: index
11959
+ };
11960
+ const instructions = detectExplicitInstructions(msg.content, source);
11961
+ allInstructions.push(...instructions);
11962
+ const hasDoNotRemember = instructions.some((i2) => i2.type === "do-not-remember");
11963
+ const hasExplicitRemember = instructions.some((i2) => i2.type === "remember");
11964
+ if (hasDoNotRemember && !hasExplicitRemember) {
11965
+ const item2 = {
11966
+ id: generateId(),
11967
+ category: "temporary_context",
11968
+ statement: msg.content,
11969
+ content: { text: msg.content, role: msg.role },
11970
+ entities: [],
11971
+ relationships: [],
11972
+ provenance: {
11973
+ source,
11974
+ classification: "temporary_context",
11975
+ confidence: "low",
11976
+ epistemicType: "observed",
11977
+ capturedAt: nowIso(),
11978
+ method: "automatic"
11979
+ },
11980
+ confidence: "low",
11981
+ epistemicType: "observed"
11982
+ };
11983
+ allItems.push(item2);
11984
+ ignored++;
11985
+ continue;
11986
+ }
11987
+ const category = classifyCategory(msg.content, instructions);
11988
+ const epistemicType = determineEpistemicType(category, msg.content, instructions);
11989
+ const confidence = determineConfidence(category, epistemicType, msg.content);
11990
+ const entities = extractEntities(msg.content);
11991
+ const relationships = extractRelationships(msg.content, entities);
11992
+ const provenance = {
11993
+ source,
11994
+ classification: category,
11995
+ confidence,
11996
+ epistemicType,
11997
+ capturedAt: nowIso(),
11998
+ method: hasExplicitRemember ? "explicit" : "automatic"
11999
+ };
12000
+ const item = {
12001
+ id: generateId(),
12002
+ category,
12003
+ statement: msg.content,
12004
+ content: { text: msg.content, role: msg.role },
12005
+ entities,
12006
+ relationships,
12007
+ provenance,
12008
+ confidence,
12009
+ epistemicType
12010
+ };
12011
+ const dedupMatches = await findExistingSimilarItems(
12012
+ msg.content,
12013
+ category,
12014
+ allItems,
12015
+ this.config.dedupSimilarityThreshold
12016
+ );
12017
+ const memoryMatches = await findExistingMemoryEntries(msg.content, category);
12018
+ const allMatches = [...dedupMatches, ...memoryMatches];
12019
+ allDedupMatches.push(...allMatches);
12020
+ let decision = "create";
12021
+ if (allMatches.length > 0) {
12022
+ const exactMatch = allMatches.find((m) => m.matchType === "exact");
12023
+ if (exactMatch) {
12024
+ decision = "link";
12025
+ linked++;
12026
+ } else {
12027
+ decision = "create";
12028
+ created++;
12029
+ }
12030
+ } else {
12031
+ created++;
12032
+ }
12033
+ const shouldStore = decision === "create" || decision === "link";
12034
+ if (shouldStore) {
12035
+ await routeToStorage(item, this.adapters, this.config);
12036
+ }
12037
+ if (!shouldStore) ignored++;
12038
+ allItems.push(item);
12039
+ }
12040
+ await this.storeSessionContext(options.conversationId, allItems, allInstructions);
12041
+ return {
12042
+ items: allItems,
12043
+ created,
12044
+ updated,
12045
+ linked,
12046
+ ignored,
12047
+ dedupMatches: allDedupMatches,
12048
+ provenance: allItems.map((i2) => i2.provenance)
12049
+ };
12050
+ }
12051
+ /**
12052
+ * Retrieve captured items for a conversation.
12053
+ */
12054
+ async getCapturedItems(conversationId) {
12055
+ const ctx = this.sessionContexts.get(conversationId);
12056
+ return ctx ? ctx.items : [];
12057
+ }
12058
+ /**
12059
+ * Get all captured items across all conversations.
12060
+ */
12061
+ async getAllCapturedItems() {
12062
+ const all = [];
12063
+ for (const ctx of this.sessionContexts.values()) {
12064
+ all.push(...ctx.items);
12065
+ }
12066
+ return all;
12067
+ }
12068
+ /**
12069
+ * Clear session context (for testing / cleanup).
12070
+ */
12071
+ clearSession(conversationId) {
12072
+ this.sessionContexts.delete(conversationId);
12073
+ }
12074
+ /**
12075
+ * Get capture engine configuration.
12076
+ */
12077
+ getConfig() {
12078
+ return { ...this.config };
12079
+ }
12080
+ // ---------------------------------------------------------------------------
12081
+ // Private
12082
+ // ---------------------------------------------------------------------------
12083
+ async storeSessionContext(conversationId, items, instructions) {
12084
+ let ctx = this.sessionContexts.get(conversationId);
12085
+ if (!ctx) {
12086
+ ctx = {
12087
+ conversationId,
12088
+ startedAt: nowIso(),
12089
+ items: [],
12090
+ explicitInstructions: []
12091
+ };
12092
+ this.sessionContexts.set(conversationId, ctx);
12093
+ }
12094
+ ctx.items.push(...items);
12095
+ ctx.explicitInstructions.push(...instructions);
12096
+ try {
12097
+ const stateKey = `${CAPTURE_STATE_KEY}:${conversationId}`;
12098
+ const existing = store.get(stateKey);
12099
+ let prior = [];
12100
+ if (existing) {
12101
+ try {
12102
+ prior = JSON.parse(existing);
12103
+ } catch {
12104
+ }
12105
+ }
12106
+ store.set(stateKey, JSON.stringify([...prior, ...items]));
12107
+ } catch {
12108
+ }
12109
+ }
12110
+ };
12111
+ captureEngine = new CaptureEngine();
12112
+ __name(captureConversation, "captureConversation");
12113
+ __name(captureTurn, "captureTurn");
12114
+ }
12115
+ });
11235
12116
 
11236
12117
  // core/memory/index.ts
11237
12118
  var memory_exports = {};
@@ -11259,6 +12140,7 @@ var init_memory = __esm({
11259
12140
  init_profile2();
11260
12141
  init_note();
11261
12142
  init_seed();
12143
+ init_capture_engine();
11262
12144
  init_security();
11263
12145
  init_detection_events();
11264
12146
  init_detection_journal();
@@ -11369,7 +12251,7 @@ var init_memory = __esm({
11369
12251
  */
11370
12252
  async clear() {
11371
12253
  await entries.clearEntries();
11372
- store.remove("__dotmem_acquired_knowledge_state__");
12254
+ store$1.remove("__dotmem_acquired_knowledge_state__");
11373
12255
  await resetKnowledgeRuntimeCaches();
11374
12256
  resetBrainPathCache();
11375
12257
  resetPolicyStoreCache();
@@ -11447,6 +12329,25 @@ var init_memory = __esm({
11447
12329
  async getSeedId() {
11448
12330
  return SEED_ID;
11449
12331
  }
12332
+ },
12333
+ /** Automatic conversational capture engine (Phase 2 — Workstream B). */
12334
+ capture: {
12335
+ engine: captureEngine,
12336
+ async conversation(messages, options) {
12337
+ return captureConversation(messages, options);
12338
+ },
12339
+ async turn(text, options) {
12340
+ return captureTurn(text, options);
12341
+ },
12342
+ async getItems(conversationId) {
12343
+ return captureEngine.getCapturedItems(conversationId);
12344
+ },
12345
+ async getAllItems() {
12346
+ return captureEngine.getAllCapturedItems();
12347
+ },
12348
+ clearSession(conversationId) {
12349
+ captureEngine.clearSession(conversationId);
12350
+ }
11450
12351
  }
11451
12352
  };
11452
12353
  }
@@ -13324,7 +14225,7 @@ Storage and session:
13324
14225
  Utilities:
13325
14226
  codenames print reserved codenames
13326
14227
  render <view> render a markdown view from the knowledge store
13327
- spark --verify verify the dotmem-scintilla block in docs/AGENTS.md
14228
+ spark --verify verify the dotmem-scintilla block in specifications/AGENTS.md
13328
14229
  note <subcommand> store and retrieve markdown files and text blocks (add|list|show|export|forget)
13329
14230
  seed <file|-> development-only: inject the Joy initial memory seed (JHF, requires \`--dev\`)
13330
14231
 
@@ -13361,13 +14262,13 @@ Examples:
13361
14262
  npx dotmem --version
13362
14263
 
13363
14264
  Learn more:
13364
- docs/AGENTS.md AI working rules and the complete memory.* surface
13365
- docs/MEMORY.md the memory reference
14265
+ specifications/agents.md AI working rules and the complete memory.* surface
14266
+ specifications/memory.md the memory reference
13366
14267
  npx dotmem policy contract acquire --json
13367
14268
  the acquisition contract`;
13368
14269
  }
13369
14270
  __name(topLevelUsage, "topLevelUsage");
13370
- function dispatch3(command, args) {
14271
+ function dispatch4(command, args) {
13371
14272
  if (!command) {
13372
14273
  void runContextCli("current project");
13373
14274
  return;
@@ -13736,7 +14637,7 @@ ids by keeping the newest copy (by acquiredAt) and retracting the shadowed one.
13736
14637
  console.info(topLevelUsage());
13737
14638
  process2.exit(1);
13738
14639
  }
13739
- __name(dispatch3, "dispatch");
14640
+ __name(dispatch4, "dispatch");
13740
14641
  async function runCodenamesCli(args) {
13741
14642
  const json = args.includes("--json");
13742
14643
  if (json) {
@@ -14702,10 +15603,10 @@ async function runDoctorCli(args) {
14702
15603
  const policyStale = [];
14703
15604
  try {
14704
15605
  const { PolicyStore: PolicyStore2 } = await Promise.resolve().then(() => (init_policy_store(), policy_store_exports));
14705
- const store5 = new PolicyStore2();
15606
+ const store6 = new PolicyStore2();
14706
15607
  for (const ns of ["operator", "security"]) {
14707
15608
  try {
14708
- const doc = await store5.load(ns);
15609
+ const doc = await store6.load(ns);
14709
15610
  for (const record of doc.records) {
14710
15611
  if (record.condition && record.condition.kind === "payload-language") {
14711
15612
  policyStale.push({ namespace: ns, id: record.id, event: record.event, condition: JSON.stringify(record.condition) });
@@ -15536,4 +16437,4 @@ function inspectMemory(file) {
15536
16437
  }
15537
16438
  __name(inspectMemory, "inspectMemory");
15538
16439
 
15539
- export { AUTHORITY_INCIDENT_TYPE, AUTHORITY_IS_RELATIONSHIP, BUILT_IN_TOOL_EVENTS, CANONICAL_BEHAVIORAL_INVARIANTS, CANONICAL_INVARIANT_IDS, CURRENT_AUTHORITY_REQUIRES_CURRENT_EVIDENCE, ContractOverlayError, DETECTION_EVENT_KINDS, DISCOVERY_PIPELINE_STAGES, DOTMEM_STORAGE_ROOT_ENV_VAR, DOTMEM_STORAGE_SETTINGS_FILE_NAME, DOTMEM_STORAGE_SETTINGS_VERSION, DotMemStorageLocationError, ENFORCEMENT_TIERS, EXPLANATION_DISPOSITIONS, EXPLANATION_REASONS, FEEDBACK_FILE_NAME, FEEDBACK_FORMAT_VERSION, HANDSHAKE_CAPABILITIES, HANDSHAKE_CHALLENGE, HANDSHAKE_VERSION, HISTORICAL_IDENTITY_NEVER_AUTHENTICATES, IDENTITY_COMPOSITION_NOT_FUSION, IDENTITY_STABLE_METADATA_SEPARATE, INCIDENT_FORBIDDEN_KEYS, IdentityGovernanceError, JO_PROFILE, LOOPS_FILE_NAME, LOOPS_FORMAT_VERSION, MAX_OVERRIDE_WINDOW_MS, MEMORY_ACQUIRE_EVENT, MEMORY_ACQUISITION_CONTRACT, MEMORY_PROJECTION_CONTRACT, MODEL_CARRIES_NOT_REDEFINES, POLICY_AUDIT_RETENTION, POLICY_LOCK_TTL_MS, POLICY_NAMESPACES, PolicyNamespaceLockError, PolicyStore, PolicyStoreError, RECOVERY_STEPS, REMEMBERING_IS_NOT_AUTHENTICATING, RENDER_FORMAT_VERSION, ROLE_MAP_FIELDS, SEED_ID, TIER_ENFORCEMENT, TOOL_EVENTS, UNAUTHORIZED_TRANSITIONS, VAULT_FILE_NAME, VAULT_FORMAT_VERSION, addLoop, assertNoConversationalOverride, authorityRelaxationPermitted, authorityRevocationPermitted, bootstrapProject, buildAuthorityIncident, buildHandshakeSessionRecord, buildPreHandshakeContract, buildTrustedRoleMap, calculateBudgetUsage, canonicalEvent, canonicalHash, canonicalPolicyFingerprint, canonicalSignature, canonicalStringify, checkHandshakeValidity, checkIdentityRenameAdmissibility, checkProjectState, clearDotMemStorageRootOverride, clearHandshakeSessionRecord, clearUserIdentity, closeLoop, computeContractRevision, computeCurrentRuntimeId, computeRuntimeId, constructEffectiveAgentContract, continuity, crossAcquisitionBoundary, describeCarrierHandshake, describeDotMemStorage, describeIdentityAndRuntime, detectAiEnvironment, detectAuthorityEscalationAttempt, detectAuthorityRoleDrift, detectBehaviorCoreMutationAttempt, detectIdentityFusion, detectIdentityMutationAttempt, detectPolicyBypassAttempt, detectSelfPromoted, detectUnauthorizedTransitions, detectUntrustedCurrentAssertion, discoverProjectSettingsFilePath, dispatch3 as dispatch, draftCorrectionExperience, encodeLogicSeed, ensureProjectAnchor, ensureUserDotMemInitialized, evaluateCarrierActivation, evaluateCarrierCompatibility, evaluateFreshness, evaluatePolicies, evaluateRoleActivation, explainBudgetAllocation, explainDiscovery, explainIdentityResolution, extractCarrierMapping, findIncidentForbiddenKey, formatBudgetExplanation, formatCheckResult, formatGuardResult, formatVerifyResult, getFeedbackForClaim, getFeedbackSummary, getLoop, getMemoryReadiness, initializeProject, injectJoySeed, inspectMem, inspectMemory, isDevSeedEnabled, isHiBound, listLoops, listViews, loadCanonicalBehavioralInvariants, loadHandshakeSessionRecord, loadIdentityGovernance, loadLoops, memory, mergeBehavioralInvariants, noteDotMemPackageInstallPath, parseContextArgs, parseHandshakeSessionRecord, parseLearnArgs, parseStorageRootFlag, preserveCanonicalIdentity, printAcquireUsage, printLearnUsage, printPolicyUsage, probeDotMemStorageCapabilities, projectAnchorExists, projectContractIdentity, readDotMemStorageLocator, readStdin, readStorageSettings, reconcileAuthorityState, reconstructCanonicalState, recordFeedback, redactTraceText, relocateDotMemStorage, renderAcquisitionContract, renderAgentRules, renderBootstrapReport, renderExplanation, renderHandshakeChallenge, renderMarkdownIndex, renderOperatorContract, renderReasoningTrace, renderView, resetCarrierHandshake, resolveAuthorityBinding, resolveDotMemStorageRoot, resolveEffectivePolicies, resolveEffectiveTier, resolveHandshakeSessionPath, resolveIdentity, resolveOverrideState, resolvePolicyNamespaceLockPath, resolveProjectIdentity, resolveProjectSettingsFilePath, resolveUserAgentMemoryPath, resolveUserAnchor, resolveUserBrainPath, resolveUserContractPath, resolveUserDotMemPath, resolveUserExperiencePath, resolveUserIdentity, resolveUserIdentityGovernancePath, resolveUserPolicyDir2 as resolveUserPolicyDir, resolveUserPolicyFilePath, resolveUserProjectMemoryPath, resolveUserReadmePath, resolveUserSettingsFilePath, restoreDefaultDotMemStorage, runAcquireCli, runAllClaimChecks, runAuthorityRecovery, runBootstrap, runCarrierHandshake, runClaimChecks, runCodenamesCli, runContext, runContextCli, runContinuityCli, runDoctorCli, runFeedbackCli, runGuardCli, runHandshakeCli, runLearnCli, runLoopCli, runNoteCli, runPolicyCli, runRenderCli, runRuleCli, runRulesCli, runSeedCli, runSessionCli, runSparkCli, runStorageCli, runVaultCli, runVerifyCli, runViolationCli, saveCorrectionDrafts, saveHandshakeSessionRecord, saveLoops, setDetectionEventSink, setDotMemStorageRootOverride, setIdentityGovernance, setUserIdentity, sha256Hex, sourceRef, suggestCorrectionPrompt, summarizeFeedbackWeights, summarizeToolPolicyDecision, topLevelUsage, validateBehavioralInvariantAdditions, validateContractOverlay, validateContractOverlays, validateFeedbackEntry, validateRetrospectiveClaim, vaultForget, vaultList, vaultPut, vaultResolve, verifyDueClaims, withPolicyNamespaceLock, withoutOverlays };
16440
+ export { AUTHORITY_INCIDENT_TYPE, AUTHORITY_IS_RELATIONSHIP, BUILT_IN_TOOL_EVENTS, CANONICAL_BEHAVIORAL_INVARIANTS, CANONICAL_INVARIANT_IDS, CURRENT_AUTHORITY_REQUIRES_CURRENT_EVIDENCE, ContractOverlayError, DETECTION_EVENT_KINDS, DISCOVERY_PIPELINE_STAGES, DOTMEM_STORAGE_ROOT_ENV_VAR, DOTMEM_STORAGE_SETTINGS_FILE_NAME, DOTMEM_STORAGE_SETTINGS_VERSION, DotMemStorageLocationError, ENFORCEMENT_TIERS, EXPLANATION_DISPOSITIONS, EXPLANATION_REASONS, FEEDBACK_FILE_NAME, FEEDBACK_FORMAT_VERSION, HANDSHAKE_CAPABILITIES, HANDSHAKE_CHALLENGE, HANDSHAKE_VERSION, HISTORICAL_IDENTITY_NEVER_AUTHENTICATES, IDENTITY_COMPOSITION_NOT_FUSION, IDENTITY_STABLE_METADATA_SEPARATE, INCIDENT_FORBIDDEN_KEYS, IdentityGovernanceError, JO_PROFILE, LOOPS_FILE_NAME, LOOPS_FORMAT_VERSION, MAX_OVERRIDE_WINDOW_MS, MEMORY_ACQUIRE_EVENT, MEMORY_ACQUISITION_CONTRACT, MEMORY_PROJECTION_CONTRACT, MODEL_CARRIES_NOT_REDEFINES, POLICY_AUDIT_RETENTION, POLICY_LOCK_TTL_MS, POLICY_NAMESPACES, PolicyNamespaceLockError, PolicyStore, PolicyStoreError, RECOVERY_STEPS, REMEMBERING_IS_NOT_AUTHENTICATING, RENDER_FORMAT_VERSION, ROLE_MAP_FIELDS, SEED_ID, TIER_ENFORCEMENT, TOOL_EVENTS, UNAUTHORIZED_TRANSITIONS, VAULT_FILE_NAME, VAULT_FORMAT_VERSION, addLoop, assertNoConversationalOverride, authorityRelaxationPermitted, authorityRevocationPermitted, bootstrapProject, buildAuthorityIncident, buildHandshakeSessionRecord, buildPreHandshakeContract, buildTrustedRoleMap, calculateBudgetUsage, canonicalEvent, canonicalHash, canonicalPolicyFingerprint, canonicalSignature, canonicalStringify, checkHandshakeValidity, checkIdentityRenameAdmissibility, checkProjectState, clearDotMemStorageRootOverride, clearHandshakeSessionRecord, clearUserIdentity, closeLoop, computeContractRevision, computeCurrentRuntimeId, computeRuntimeId, constructEffectiveAgentContract, continuity, crossAcquisitionBoundary, describeCarrierHandshake, describeDotMemStorage, describeIdentityAndRuntime, detectAiEnvironment, detectAuthorityEscalationAttempt, detectAuthorityRoleDrift, detectBehaviorCoreMutationAttempt, detectIdentityFusion, detectIdentityMutationAttempt, detectPolicyBypassAttempt, detectSelfPromoted, detectUnauthorizedTransitions, detectUntrustedCurrentAssertion, discoverProjectSettingsFilePath, dispatch4 as dispatch, draftCorrectionExperience, encodeLogicSeed, ensureProjectAnchor, ensureUserDotMemInitialized, evaluateCarrierActivation, evaluateCarrierCompatibility, evaluateFreshness, evaluatePolicies, evaluateRoleActivation, explainBudgetAllocation, explainDiscovery, explainIdentityResolution, extractCarrierMapping, findIncidentForbiddenKey, formatBudgetExplanation, formatCheckResult, formatGuardResult, formatVerifyResult, getFeedbackForClaim, getFeedbackSummary, getLoop, getMemoryReadiness, initializeProject, injectJoySeed, inspectMem, inspectMemory, isDevSeedEnabled, isHiBound, listLoops, listViews, loadCanonicalBehavioralInvariants, loadHandshakeSessionRecord, loadIdentityGovernance, loadLoops, memory, mergeBehavioralInvariants, noteDotMemPackageInstallPath, parseContextArgs, parseHandshakeSessionRecord, parseLearnArgs, parseStorageRootFlag, preserveCanonicalIdentity, printAcquireUsage, printLearnUsage, printPolicyUsage, probeDotMemStorageCapabilities, projectAnchorExists, projectContractIdentity, readDotMemStorageLocator, readStdin, readStorageSettings, reconcileAuthorityState, reconstructCanonicalState, recordFeedback, redactTraceText, relocateDotMemStorage, renderAcquisitionContract, renderAgentRules, renderBootstrapReport, renderExplanation, renderHandshakeChallenge, renderMarkdownIndex, renderOperatorContract, renderReasoningTrace, renderView, resetCarrierHandshake, resolveAuthorityBinding, resolveDotMemStorageRoot, resolveEffectivePolicies, resolveEffectiveTier, resolveHandshakeSessionPath, resolveIdentity, resolveOverrideState, resolvePolicyNamespaceLockPath, resolveProjectIdentity, resolveProjectSettingsFilePath, resolveUserAgentMemoryPath, resolveUserAnchor, resolveUserBrainPath, resolveUserContractPath, resolveUserDotMemPath, resolveUserExperiencePath, resolveUserIdentity, resolveUserIdentityGovernancePath, resolveUserPolicyDir2 as resolveUserPolicyDir, resolveUserPolicyFilePath, resolveUserProjectMemoryPath, resolveUserReadmePath, resolveUserSettingsFilePath, restoreDefaultDotMemStorage, runAcquireCli, runAllClaimChecks, runAuthorityRecovery, runBootstrap, runCarrierHandshake, runClaimChecks, runCodenamesCli, runContext, runContextCli, runContinuityCli, runDoctorCli, runFeedbackCli, runGuardCli, runHandshakeCli, runLearnCli, runLoopCli, runNoteCli, runPolicyCli, runRenderCli, runRuleCli, runRulesCli, runSeedCli, runSessionCli, runSparkCli, runStorageCli, runVaultCli, runVerifyCli, runViolationCli, saveCorrectionDrafts, saveHandshakeSessionRecord, saveLoops, setDetectionEventSink, setDotMemStorageRootOverride, setIdentityGovernance, setUserIdentity, sha256Hex, sourceRef, suggestCorrectionPrompt, summarizeFeedbackWeights, summarizeToolPolicyDecision, topLevelUsage, validateBehavioralInvariantAdditions, validateContractOverlay, validateContractOverlays, validateFeedbackEntry, validateRetrospectiveClaim, vaultForget, vaultList, vaultPut, vaultResolve, verifyDueClaims, withPolicyNamespaceLock, withoutOverlays };