memorix 1.2.10 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +28 -2
  3. package/README.zh-CN.md +28 -2
  4. package/assets/star-history-dark.svg +30 -0
  5. package/assets/star-history-light.svg +30 -0
  6. package/assets/star-history.json +599 -0
  7. package/dist/cli/index.js +1783 -557
  8. package/dist/cli/index.js.map +1 -1
  9. package/dist/index.js +1292 -267
  10. package/dist/index.js.map +1 -1
  11. package/dist/maintenance-runner.js +97 -21
  12. package/dist/maintenance-runner.js.map +1 -1
  13. package/dist/memcode-runtime/CHANGELOG.md +15 -0
  14. package/dist/sdk.d.ts +1 -1
  15. package/dist/sdk.js +1294 -269
  16. package/dist/sdk.js.map +1 -1
  17. package/dist/types.d.ts +99 -1
  18. package/dist/types.js.map +1 -1
  19. package/dist/vector-backfill-runner.js +97 -21
  20. package/dist/vector-backfill-runner.js.map +1 -1
  21. package/docs/1.3-MEMORY-ARCHITECTURE.md +236 -0
  22. package/docs/AGENT_OPERATOR_PLAYBOOK.md +3 -1
  23. package/docs/API_REFERENCE.md +20 -1
  24. package/docs/ARCHITECTURE.md +34 -1
  25. package/docs/DEVELOPMENT.md +3 -2
  26. package/docs/MODULES.md +27 -1
  27. package/docs/README.md +3 -3
  28. package/docs/dev-log/progress.txt +22 -0
  29. package/llms-full.txt +5 -1
  30. package/llms.txt +2 -0
  31. package/package.json +2 -1
  32. package/plugins/antigravity/memorix/rules/memorix.md +2 -0
  33. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  34. package/plugins/claude/memorix/skills/memorix-memory/SKILL.md +3 -0
  35. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  36. package/plugins/codex/memorix/skills/memorix-memory/SKILL.md +3 -0
  37. package/plugins/copilot/memorix/plugin.json +1 -1
  38. package/plugins/copilot/memorix/skills/memorix-memory/SKILL.md +3 -0
  39. package/plugins/cursor/memorix/skills/memorix-memory/SKILL.md +3 -0
  40. package/plugins/gemini/memorix/GEMINI.md +2 -0
  41. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  42. package/plugins/omp/memorix/package.json +1 -1
  43. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  44. package/plugins/pi/memorix/package.json +1 -1
  45. package/plugins/pi/memorix/skills/memorix-memory/SKILL.md +3 -0
  46. package/server.json +2 -2
  47. package/src/cli/command-guide.ts +9 -1
  48. package/src/cli/commands/codegraph.ts +1 -0
  49. package/src/cli/commands/memory.ts +217 -1
  50. package/src/codegraph/auto-context.ts +11 -0
  51. package/src/codegraph/context-pack.ts +3 -0
  52. package/src/embedding/api-provider.ts +23 -9
  53. package/src/embedding/provider.ts +21 -10
  54. package/src/hooks/installers/index.ts +2 -0
  55. package/src/knowledge/context-assembly.ts +2 -1
  56. package/src/knowledge/workset.ts +77 -4
  57. package/src/memory/long-term-store.ts +242 -0
  58. package/src/memory/long-term-types.ts +136 -0
  59. package/src/memory/long-term.ts +626 -0
  60. package/src/memory/owner.ts +75 -0
  61. package/src/server.ts +112 -30
  62. package/src/store/sqlite-db.ts +74 -0
  63. package/src/types.ts +20 -0
package/dist/cli/index.js CHANGED
@@ -3212,7 +3212,7 @@ ${import_picocolors.default.gray(m3)} ${s2}
3212
3212
 
3213
3213
  // src/cli/version.ts
3214
3214
  function getCliVersion() {
3215
- return true ? "1.2.10" : pkg.version;
3215
+ return true ? "1.3.0" : pkg.version;
3216
3216
  }
3217
3217
  var init_version = __esm({
3218
3218
  "src/cli/version.ts"() {
@@ -3529,15 +3529,15 @@ function getDocumentProperties(doc, paths) {
3529
3529
  const properties = {};
3530
3530
  const pathsLength = paths.length;
3531
3531
  for (let i2 = 0; i2 < pathsLength; i2++) {
3532
- const path37 = paths[i2];
3533
- const pathTokens = path37.split(".");
3532
+ const path38 = paths[i2];
3533
+ const pathTokens = path38.split(".");
3534
3534
  let current = doc;
3535
3535
  const pathTokensLength = pathTokens.length;
3536
3536
  for (let j3 = 0; j3 < pathTokensLength; j3++) {
3537
3537
  current = current[pathTokens[j3]];
3538
3538
  if (typeof current === "object") {
3539
3539
  if (current !== null && "lat" in current && "lon" in current && typeof current.lat === "number" && typeof current.lon === "number") {
3540
- current = properties[path37] = current;
3540
+ current = properties[path38] = current;
3541
3541
  break;
3542
3542
  } else if (!Array.isArray(current) && current !== null && j3 === pathTokensLength - 1) {
3543
3543
  current = void 0;
@@ -3549,14 +3549,14 @@ function getDocumentProperties(doc, paths) {
3549
3549
  }
3550
3550
  }
3551
3551
  if (typeof current !== "undefined") {
3552
- properties[path37] = current;
3552
+ properties[path38] = current;
3553
3553
  }
3554
3554
  }
3555
3555
  return properties;
3556
3556
  }
3557
- function getNested(obj, path37) {
3558
- const props = getDocumentProperties(obj, [path37]);
3559
- return props[path37];
3557
+ function getNested(obj, path38) {
3558
+ const props = getDocumentProperties(obj, [path38]);
3559
+ return props[path38];
3560
3560
  }
3561
3561
  function convertDistanceToMeters(distance, unit) {
3562
3562
  const ratio = mapDistanceToMeters[unit];
@@ -3572,10 +3572,10 @@ function removeVectorsFromHits(searchResult, vectorProperties) {
3572
3572
  ...result.document,
3573
3573
  // Remove embeddings from the result
3574
3574
  ...vectorProperties.reduce((acc, prop) => {
3575
- const path37 = prop.split(".");
3576
- const lastKey = path37.pop();
3575
+ const path38 = prop.split(".");
3576
+ const lastKey = path38.pop();
3577
3577
  let obj = acc;
3578
- for (const key of path37) {
3578
+ for (const key of path38) {
3579
3579
  obj[key] = obj[key] ?? {};
3580
3580
  obj = obj[key];
3581
3581
  }
@@ -4307,15 +4307,15 @@ var init_avl = __esm({
4307
4307
  if (node === null) {
4308
4308
  return new AVLNode(key, [value]);
4309
4309
  }
4310
- const path37 = [];
4310
+ const path38 = [];
4311
4311
  let current = node;
4312
4312
  let parent = null;
4313
4313
  while (current !== null) {
4314
- path37.push({ parent, node: current });
4314
+ path38.push({ parent, node: current });
4315
4315
  if (key < current.k) {
4316
4316
  if (current.l === null) {
4317
4317
  current.l = new AVLNode(key, [value]);
4318
- path37.push({ parent: current, node: current.l });
4318
+ path38.push({ parent: current, node: current.l });
4319
4319
  break;
4320
4320
  } else {
4321
4321
  parent = current;
@@ -4324,7 +4324,7 @@ var init_avl = __esm({
4324
4324
  } else if (key > current.k) {
4325
4325
  if (current.r === null) {
4326
4326
  current.r = new AVLNode(key, [value]);
4327
- path37.push({ parent: current, node: current.r });
4327
+ path38.push({ parent: current, node: current.r });
4328
4328
  break;
4329
4329
  } else {
4330
4330
  parent = current;
@@ -4339,8 +4339,8 @@ var init_avl = __esm({
4339
4339
  if (this.insertCount++ % rebalanceThreshold === 0) {
4340
4340
  needRebalance = true;
4341
4341
  }
4342
- for (let i2 = path37.length - 1; i2 >= 0; i2--) {
4343
- const { parent: parent2, node: currentNode } = path37[i2];
4342
+ for (let i2 = path38.length - 1; i2 >= 0; i2--) {
4343
+ const { parent: parent2, node: currentNode } = path38[i2];
4344
4344
  currentNode.updateHeight();
4345
4345
  if (needRebalance) {
4346
4346
  const rebalancedNode = this.rebalanceNode(currentNode);
@@ -4446,10 +4446,10 @@ var init_avl = __esm({
4446
4446
  removeNode(node, key) {
4447
4447
  if (node === null)
4448
4448
  return null;
4449
- const path37 = [];
4449
+ const path38 = [];
4450
4450
  let current = node;
4451
4451
  while (current !== null && current.k !== key) {
4452
- path37.push(current);
4452
+ path38.push(current);
4453
4453
  if (key < current.k) {
4454
4454
  current = current.l;
4455
4455
  } else {
@@ -4461,10 +4461,10 @@ var init_avl = __esm({
4461
4461
  }
4462
4462
  if (current.l === null || current.r === null) {
4463
4463
  const child = current.l ? current.l : current.r;
4464
- if (path37.length === 0) {
4464
+ if (path38.length === 0) {
4465
4465
  node = child;
4466
4466
  } else {
4467
- const parent = path37[path37.length - 1];
4467
+ const parent = path38[path38.length - 1];
4468
4468
  if (parent.l === current) {
4469
4469
  parent.l = child;
4470
4470
  } else {
@@ -4487,13 +4487,13 @@ var init_avl = __esm({
4487
4487
  }
4488
4488
  current = successorParent;
4489
4489
  }
4490
- path37.push(current);
4491
- for (let i2 = path37.length - 1; i2 >= 0; i2--) {
4492
- const currentNode = path37[i2];
4490
+ path38.push(current);
4491
+ for (let i2 = path38.length - 1; i2 >= 0; i2--) {
4492
+ const currentNode = path38[i2];
4493
4493
  currentNode.updateHeight();
4494
4494
  const rebalancedNode = this.rebalanceNode(currentNode);
4495
4495
  if (i2 > 0) {
4496
- const parent = path37[i2 - 1];
4496
+ const parent = path38[i2 - 1];
4497
4497
  if (parent.l === currentNode) {
4498
4498
  parent.l = rebalancedNode;
4499
4499
  } else if (parent.r === currentNode) {
@@ -5660,15 +5660,15 @@ function create2(orama, sharedInternalDocumentStore, schema, index, prefix = "")
5660
5660
  };
5661
5661
  }
5662
5662
  for (const [prop, type] of Object.entries(schema)) {
5663
- const path37 = `${prefix}${prefix ? "." : ""}${prop}`;
5663
+ const path38 = `${prefix}${prefix ? "." : ""}${prop}`;
5664
5664
  if (typeof type === "object" && !Array.isArray(type)) {
5665
- create2(orama, sharedInternalDocumentStore, type, index, path37);
5665
+ create2(orama, sharedInternalDocumentStore, type, index, path38);
5666
5666
  continue;
5667
5667
  }
5668
5668
  if (isVectorType(type)) {
5669
- index.searchableProperties.push(path37);
5670
- index.searchablePropertiesWithTypes[path37] = type;
5671
- index.vectorIndexes[path37] = {
5669
+ index.searchableProperties.push(path38);
5670
+ index.searchablePropertiesWithTypes[path38] = type;
5671
+ index.vectorIndexes[path38] = {
5672
5672
  type: "Vector",
5673
5673
  node: new VectorIndex(getVectorSize(type)),
5674
5674
  isArray: false
@@ -5678,32 +5678,32 @@ function create2(orama, sharedInternalDocumentStore, schema, index, prefix = "")
5678
5678
  switch (type) {
5679
5679
  case "boolean":
5680
5680
  case "boolean[]":
5681
- index.indexes[path37] = { type: "Bool", node: new BoolNode(), isArray };
5681
+ index.indexes[path38] = { type: "Bool", node: new BoolNode(), isArray };
5682
5682
  break;
5683
5683
  case "number":
5684
5684
  case "number[]":
5685
- index.indexes[path37] = { type: "AVL", node: new AVLTree(0, []), isArray };
5685
+ index.indexes[path38] = { type: "AVL", node: new AVLTree(0, []), isArray };
5686
5686
  break;
5687
5687
  case "string":
5688
5688
  case "string[]":
5689
- index.indexes[path37] = { type: "Radix", node: new RadixTree(), isArray };
5690
- index.avgFieldLength[path37] = 0;
5691
- index.frequencies[path37] = {};
5692
- index.tokenOccurrences[path37] = {};
5693
- index.fieldLengths[path37] = {};
5689
+ index.indexes[path38] = { type: "Radix", node: new RadixTree(), isArray };
5690
+ index.avgFieldLength[path38] = 0;
5691
+ index.frequencies[path38] = {};
5692
+ index.tokenOccurrences[path38] = {};
5693
+ index.fieldLengths[path38] = {};
5694
5694
  break;
5695
5695
  case "enum":
5696
5696
  case "enum[]":
5697
- index.indexes[path37] = { type: "Flat", node: new FlatTree(), isArray };
5697
+ index.indexes[path38] = { type: "Flat", node: new FlatTree(), isArray };
5698
5698
  break;
5699
5699
  case "geopoint":
5700
- index.indexes[path37] = { type: "BKD", node: new BKDTree(), isArray };
5700
+ index.indexes[path38] = { type: "BKD", node: new BKDTree(), isArray };
5701
5701
  break;
5702
5702
  default:
5703
- throw createError("INVALID_SCHEMA_TYPE", Array.isArray(type) ? "array" : type, path37);
5703
+ throw createError("INVALID_SCHEMA_TYPE", Array.isArray(type) ? "array" : type, path38);
5704
5704
  }
5705
- index.searchableProperties.push(path37);
5706
- index.searchablePropertiesWithTypes[path37] = type;
5705
+ index.searchableProperties.push(path38);
5706
+ index.searchablePropertiesWithTypes[path38] = type;
5707
5707
  }
5708
5708
  }
5709
5709
  return index;
@@ -6274,12 +6274,12 @@ function innerCreate(orama, sharedInternalDocumentStore, schema, sortableDeniedP
6274
6274
  sorts: {}
6275
6275
  };
6276
6276
  for (const [prop, type] of Object.entries(schema)) {
6277
- const path37 = `${prefix}${prefix ? "." : ""}${prop}`;
6278
- if (sortableDeniedProperties.includes(path37)) {
6277
+ const path38 = `${prefix}${prefix ? "." : ""}${prop}`;
6278
+ if (sortableDeniedProperties.includes(path38)) {
6279
6279
  continue;
6280
6280
  }
6281
6281
  if (typeof type === "object" && !Array.isArray(type)) {
6282
- const ret = innerCreate(orama, sharedInternalDocumentStore, type, sortableDeniedProperties, path37);
6282
+ const ret = innerCreate(orama, sharedInternalDocumentStore, type, sortableDeniedProperties, path38);
6283
6283
  safeArrayPush(sorter.sortableProperties, ret.sortableProperties);
6284
6284
  sorter.sorts = {
6285
6285
  ...sorter.sorts,
@@ -6296,9 +6296,9 @@ function innerCreate(orama, sharedInternalDocumentStore, schema, sortableDeniedP
6296
6296
  case "boolean":
6297
6297
  case "number":
6298
6298
  case "string":
6299
- sorter.sortableProperties.push(path37);
6300
- sorter.sortablePropertiesWithTypes[path37] = type;
6301
- sorter.sorts[path37] = {
6299
+ sorter.sortableProperties.push(path38);
6300
+ sorter.sortablePropertiesWithTypes[path38] = type;
6301
+ sorter.sorts[path38] = {
6302
6302
  docs: /* @__PURE__ */ new Map(),
6303
6303
  orderedDocsToRemove: /* @__PURE__ */ new Map(),
6304
6304
  orderedDocs: [],
@@ -6314,7 +6314,7 @@ function innerCreate(orama, sharedInternalDocumentStore, schema, sortableDeniedP
6314
6314
  case "string[]":
6315
6315
  continue;
6316
6316
  default:
6317
- throw createError("INVALID_SORT_SCHEMA_TYPE", Array.isArray(type) ? "array" : type, path37);
6317
+ throw createError("INVALID_SORT_SCHEMA_TYPE", Array.isArray(type) ? "array" : type, path38);
6318
6318
  }
6319
6319
  }
6320
6320
  }
@@ -8159,8 +8159,8 @@ function innerFullTextSearch(orama, params, language) {
8159
8159
  function escapeRegex(str2) {
8160
8160
  return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8161
8161
  }
8162
- function getPropValue(obj, path37) {
8163
- const keys = path37.split(".");
8162
+ function getPropValue(obj, path38) {
8163
+ const keys = path38.split(".");
8164
8164
  let value = obj;
8165
8165
  for (const key of keys) {
8166
8166
  if (value && typeof value === "object" && key in value) {
@@ -9219,15 +9219,15 @@ function loadSqlite() {
9219
9219
  throw new Error("[memorix] SQLite is unavailable (better-sqlite3, node:sqlite, and bun:sqlite failed)");
9220
9220
  }
9221
9221
  }
9222
- function createDatabase(path37, options2) {
9222
+ function createDatabase(path38, options2) {
9223
9223
  const Sqlite = loadSqlite();
9224
9224
  try {
9225
- return addCompatibility(instantiateDatabase(Sqlite, path37, options2));
9225
+ return addCompatibility(instantiateDatabase(Sqlite, path38, options2));
9226
9226
  } catch (error2) {
9227
9227
  if (driver !== "better-sqlite3" || !isNativeBindingFailure(error2)) throw error2;
9228
9228
  Database = loadNodeSqlite();
9229
9229
  driver = "node:sqlite";
9230
- return addCompatibility(instantiateDatabase(Database, path37, options2));
9230
+ return addCompatibility(instantiateDatabase(Database, path38, options2));
9231
9231
  }
9232
9232
  }
9233
9233
  var Database, driver, requireFromHere;
@@ -9354,7 +9354,7 @@ function closeAllDatabases() {
9354
9354
  _dbCache.delete(key);
9355
9355
  }
9356
9356
  }
9357
- var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
9357
+ var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
9358
9358
  var init_sqlite_db = __esm({
9359
9359
  "src/store/sqlite-db.ts"() {
9360
9360
  "use strict";
@@ -9780,6 +9780,57 @@ CREATE TABLE IF NOT EXISTS knowledge_claim_events (
9780
9780
  " FOREIGN KEY (workflowId) REFERENCES knowledge_workflows(id) ON DELETE CASCADE",
9781
9781
  ");"
9782
9782
  ].join("\n");
9783
+ CREATE_LONG_TERM_MEMORIES_TABLE = `
9784
+ CREATE TABLE IF NOT EXISTS long_term_memories (
9785
+ id TEXT PRIMARY KEY,
9786
+ originProjectId TEXT NOT NULL,
9787
+ ownerId TEXT NOT NULL,
9788
+ scope TEXT NOT NULL,
9789
+ kind TEXT NOT NULL,
9790
+ state TEXT NOT NULL,
9791
+ portability TEXT NOT NULL DEFAULT 'project-bound',
9792
+ title TEXT NOT NULL,
9793
+ content TEXT NOT NULL,
9794
+ factsJson TEXT NOT NULL DEFAULT '[]',
9795
+ tagsJson TEXT NOT NULL DEFAULT '[]',
9796
+ applicability TEXT,
9797
+ origin TEXT NOT NULL,
9798
+ createdAt TEXT NOT NULL,
9799
+ updatedAt TEXT NOT NULL,
9800
+ qualifiedAt TEXT,
9801
+ approvedAt TEXT,
9802
+ archivedAt TEXT,
9803
+ supersededBy TEXT,
9804
+ lastValidatedAt TEXT,
9805
+ accessCount INTEGER NOT NULL DEFAULT 0,
9806
+ lastAccessedAt TEXT
9807
+ );
9808
+ `;
9809
+ CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE = `
9810
+ CREATE TABLE IF NOT EXISTS long_term_memory_evidence (
9811
+ id TEXT PRIMARY KEY,
9812
+ memoryId TEXT NOT NULL,
9813
+ kind TEXT NOT NULL,
9814
+ referenceId TEXT NOT NULL,
9815
+ relation TEXT NOT NULL,
9816
+ locator TEXT,
9817
+ capturedHash TEXT,
9818
+ createdAt TEXT NOT NULL,
9819
+ FOREIGN KEY (memoryId) REFERENCES long_term_memories(id) ON DELETE CASCADE
9820
+ );
9821
+ `;
9822
+ CREATE_LONG_TERM_MEMORY_EVENTS_TABLE = `
9823
+ CREATE TABLE IF NOT EXISTS long_term_memory_events (
9824
+ id TEXT PRIMARY KEY,
9825
+ memoryId TEXT NOT NULL,
9826
+ kind TEXT NOT NULL,
9827
+ fromState TEXT,
9828
+ toState TEXT,
9829
+ detail TEXT,
9830
+ createdAt TEXT NOT NULL,
9831
+ FOREIGN KEY (memoryId) REFERENCES long_term_memories(id) ON DELETE CASCADE
9832
+ );
9833
+ `;
9783
9834
  CREATE_MAINTENANCE_JOBS_TABLE = `
9784
9835
  CREATE TABLE IF NOT EXISTS maintenance_jobs (
9785
9836
  id TEXT PRIMARY KEY,
@@ -9875,6 +9926,11 @@ CREATE INDEX IF NOT EXISTS idx_knowledge_page_claims_claim ON knowledge_page_cla
9875
9926
  CREATE INDEX IF NOT EXISTS idx_knowledge_proposals_workspace_status ON knowledge_proposals(workspaceId, status, createdAt DESC);
9876
9927
  CREATE INDEX IF NOT EXISTS idx_knowledge_workflows_workspace_status ON knowledge_workflows(workspaceId, status, updatedAt DESC);
9877
9928
  CREATE INDEX IF NOT EXISTS idx_knowledge_workflow_runs_project_workflow ON knowledge_workflow_runs(projectId, workflowId, startedAt DESC);
9929
+ CREATE INDEX IF NOT EXISTS idx_long_term_memories_owner_state ON long_term_memories(ownerId, state, updatedAt DESC);
9930
+ CREATE INDEX IF NOT EXISTS idx_long_term_memories_project_state ON long_term_memories(originProjectId, state, updatedAt DESC);
9931
+ CREATE INDEX IF NOT EXISTS idx_long_term_memories_scope_portability ON long_term_memories(scope, portability, state, updatedAt DESC);
9932
+ CREATE INDEX IF NOT EXISTS idx_long_term_memory_evidence_memory ON long_term_memory_evidence(memoryId, createdAt);
9933
+ CREATE INDEX IF NOT EXISTS idx_long_term_memory_events_memory ON long_term_memory_events(memoryId, createdAt);
9878
9934
  CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_ready ON maintenance_jobs(status, run_after);
9879
9935
  CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_project ON maintenance_jobs(project_id, status, run_after);
9880
9936
  CREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_targets(updated_at);
@@ -9963,6 +10019,19 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
9963
10019
  db2.exec("CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC)");
9964
10020
  db2.exec("CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key)");
9965
10021
  }
10022
+ },
10023
+ {
10024
+ id: "1.3-long-term-memory",
10025
+ apply: (db2) => {
10026
+ db2.exec(CREATE_LONG_TERM_MEMORIES_TABLE);
10027
+ db2.exec(CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE);
10028
+ db2.exec(CREATE_LONG_TERM_MEMORY_EVENTS_TABLE);
10029
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_long_term_memories_owner_state ON long_term_memories(ownerId, state, updatedAt DESC)");
10030
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_long_term_memories_project_state ON long_term_memories(originProjectId, state, updatedAt DESC)");
10031
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_long_term_memories_scope_portability ON long_term_memories(scope, portability, state, updatedAt DESC)");
10032
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_long_term_memory_evidence_memory ON long_term_memory_evidence(memoryId, createdAt)");
10033
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_long_term_memory_events_memory ON long_term_memory_events(memoryId, createdAt)");
10034
+ }
9966
10035
  }
9967
10036
  ];
9968
10037
  _dbCache = /* @__PURE__ */ new Map();
@@ -13292,9 +13361,9 @@ function parseTomlConfig(content, filePath) {
13292
13361
  }
13293
13362
  return root;
13294
13363
  }
13295
- function ensureTable(root, path37) {
13364
+ function ensureTable(root, path38) {
13296
13365
  let cursor = root;
13297
- for (const part of path37) {
13366
+ for (const part of path38) {
13298
13367
  const value = cursor[part];
13299
13368
  if (!value || typeof value !== "object" || Array.isArray(value)) {
13300
13369
  cursor[part] = {};
@@ -13428,8 +13497,8 @@ var require_main = __commonJS({
13428
13497
  "node_modules/dotenv/lib/main.js"(exports2, module2) {
13429
13498
  "use strict";
13430
13499
  init_esm_shims();
13431
- var fs27 = __require("fs");
13432
- var path37 = __require("path");
13500
+ var fs28 = __require("fs");
13501
+ var path38 = __require("path");
13433
13502
  var os5 = __require("os");
13434
13503
  var crypto3 = __require("crypto");
13435
13504
  var packageJson = require_package();
@@ -13567,7 +13636,7 @@ var require_main = __commonJS({
13567
13636
  if (options2 && options2.path && options2.path.length > 0) {
13568
13637
  if (Array.isArray(options2.path)) {
13569
13638
  for (const filepath of options2.path) {
13570
- if (fs27.existsSync(filepath)) {
13639
+ if (fs28.existsSync(filepath)) {
13571
13640
  possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
13572
13641
  }
13573
13642
  }
@@ -13575,15 +13644,15 @@ var require_main = __commonJS({
13575
13644
  possibleVaultPath = options2.path.endsWith(".vault") ? options2.path : `${options2.path}.vault`;
13576
13645
  }
13577
13646
  } else {
13578
- possibleVaultPath = path37.resolve(process.cwd(), ".env.vault");
13647
+ possibleVaultPath = path38.resolve(process.cwd(), ".env.vault");
13579
13648
  }
13580
- if (fs27.existsSync(possibleVaultPath)) {
13649
+ if (fs28.existsSync(possibleVaultPath)) {
13581
13650
  return possibleVaultPath;
13582
13651
  }
13583
13652
  return null;
13584
13653
  }
13585
13654
  function _resolveHome(envPath) {
13586
- return envPath[0] === "~" ? path37.join(os5.homedir(), envPath.slice(1)) : envPath;
13655
+ return envPath[0] === "~" ? path38.join(os5.homedir(), envPath.slice(1)) : envPath;
13587
13656
  }
13588
13657
  function _configVault(options2) {
13589
13658
  const debug = parseBoolean(process.env.DOTENV_CONFIG_DEBUG || options2 && options2.debug);
@@ -13600,7 +13669,7 @@ var require_main = __commonJS({
13600
13669
  return { parsed };
13601
13670
  }
13602
13671
  function configDotenv(options2) {
13603
- const dotenvPath = path37.resolve(process.cwd(), ".env");
13672
+ const dotenvPath = path38.resolve(process.cwd(), ".env");
13604
13673
  let encoding = "utf8";
13605
13674
  let processEnv = process.env;
13606
13675
  if (options2 && options2.processEnv != null) {
@@ -13628,13 +13697,13 @@ var require_main = __commonJS({
13628
13697
  }
13629
13698
  let lastError;
13630
13699
  const parsedAll = {};
13631
- for (const path38 of optionPaths) {
13700
+ for (const path39 of optionPaths) {
13632
13701
  try {
13633
- const parsed = DotenvModule.parse(fs27.readFileSync(path38, { encoding }));
13702
+ const parsed = DotenvModule.parse(fs28.readFileSync(path39, { encoding }));
13634
13703
  DotenvModule.populate(parsedAll, parsed, options2);
13635
13704
  } catch (e3) {
13636
13705
  if (debug) {
13637
- _debug(`Failed to load ${path38} ${e3.message}`);
13706
+ _debug(`Failed to load ${path39} ${e3.message}`);
13638
13707
  }
13639
13708
  lastError = e3;
13640
13709
  }
@@ -13647,7 +13716,7 @@ var require_main = __commonJS({
13647
13716
  const shortPaths = [];
13648
13717
  for (const filePath of optionPaths) {
13649
13718
  try {
13650
- const relative3 = path37.relative(process.cwd(), filePath);
13719
+ const relative3 = path38.relative(process.cwd(), filePath);
13651
13720
  shortPaths.push(relative3);
13652
13721
  } catch (e3) {
13653
13722
  if (debug) {
@@ -14566,9 +14635,10 @@ function parseBatchLimit(error2) {
14566
14635
  }
14567
14636
  return null;
14568
14637
  }
14569
- async function fetchWithRetry(url, apiKey, body, attempt = 0) {
14638
+ async function fetchWithRetry(url, apiKey, body, options2 = {}, attempt = 0) {
14570
14639
  const controller = new AbortController();
14571
- const timeout = setTimeout(() => controller.abort(), 1e4);
14640
+ const timeoutMs = typeof options2.timeoutMs === "number" && Number.isFinite(options2.timeoutMs) ? Math.max(100, Math.min(Math.floor(options2.timeoutMs), 6e4)) : 1e4;
14641
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
14572
14642
  let response;
14573
14643
  try {
14574
14644
  response = await fetch(url, {
@@ -14583,7 +14653,7 @@ async function fetchWithRetry(url, apiKey, body, attempt = 0) {
14583
14653
  } catch (err) {
14584
14654
  clearTimeout(timeout);
14585
14655
  if (err instanceof Error && err.name === "AbortError") {
14586
- throw new Error(`Embedding API timeout after 10s: ${url}`);
14656
+ throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url}`);
14587
14657
  }
14588
14658
  throw err;
14589
14659
  }
@@ -14591,13 +14661,13 @@ async function fetchWithRetry(url, apiKey, body, attempt = 0) {
14591
14661
  if (response.ok) {
14592
14662
  return response.json();
14593
14663
  }
14594
- if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
14664
+ if (options2.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
14595
14665
  const delay = BASE_DELAY_MS * Math.pow(2, attempt);
14596
14666
  const retryAfter = response.headers.get("retry-after");
14597
14667
  const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1e3 : delay;
14598
14668
  console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
14599
14669
  await new Promise((resolve6) => setTimeout(resolve6, waitMs));
14600
- return fetchWithRetry(url, apiKey, body, attempt + 1);
14670
+ return fetchWithRetry(url, apiKey, body, options2, attempt + 1);
14601
14671
  }
14602
14672
  const errorText2 = await response.text().catch(() => "unknown error");
14603
14673
  throw new Error(`Embedding API error (${response.status}): ${errorText2}`);
@@ -14653,7 +14723,10 @@ var init_api_provider = __esm({
14653
14723
  }
14654
14724
  } else {
14655
14725
  if (!allowNetworkProbe) return null;
14656
- probeDimensions = await _APIEmbeddingProvider.probeAPI(config2);
14726
+ probeDimensions = await _APIEmbeddingProvider.probeAPI(config2, {
14727
+ timeoutMs: options2.requestTimeoutMs,
14728
+ retry: options2.retry
14729
+ });
14657
14730
  console.error(`[memorix] API embedding: ${config2.model} @ ${config2.baseUrl} (${probeDimensions}d)`);
14658
14731
  saveCachedDims(config2, probeDimensions).catch(() => {
14659
14732
  });
@@ -14695,7 +14768,7 @@ var init_api_provider = __esm({
14695
14768
  baseUrl = baseUrl.replace(/\/+$/, "");
14696
14769
  return { apiKey, baseUrl, model, requestedDimensions };
14697
14770
  }
14698
- static async probeAPI(config2) {
14771
+ static async probeAPI(config2, options2) {
14699
14772
  const body = {
14700
14773
  model: config2.model,
14701
14774
  input: "dimension probe"
@@ -14706,14 +14779,15 @@ var init_api_provider = __esm({
14706
14779
  const response = await fetchWithRetry(
14707
14780
  `${config2.baseUrl}/embeddings`,
14708
14781
  config2.apiKey,
14709
- body
14782
+ body,
14783
+ options2
14710
14784
  );
14711
14785
  if (response.data.length === 0 || !response.data[0].embedding) {
14712
14786
  throw new Error("API probe returned no embeddings; check model name and API key");
14713
14787
  }
14714
14788
  return response.data[0].embedding.length;
14715
14789
  }
14716
- async embed(text) {
14790
+ async embed(text, options2) {
14717
14791
  const normalized = normalizeText(text);
14718
14792
  const hash4 = textHash2(normalized, this.cacheKeyNamespace);
14719
14793
  if (diskCacheLoaded) {
@@ -14731,7 +14805,8 @@ var init_api_provider = __esm({
14731
14805
  const response = await fetchWithRetry(
14732
14806
  `${this.config.baseUrl}/embeddings`,
14733
14807
  this.config.apiKey,
14734
- body
14808
+ body,
14809
+ options2
14735
14810
  );
14736
14811
  const embedding2 = response.data[0].embedding;
14737
14812
  if (embedding2.length !== this.dimensions) {
@@ -14765,7 +14840,7 @@ var init_api_provider = __esm({
14765
14840
  scheduleDiskSave();
14766
14841
  return embedding;
14767
14842
  }
14768
- async embedBatch(texts) {
14843
+ async embedBatch(texts, options2) {
14769
14844
  await ensureDiskCacheLoaded();
14770
14845
  const normalizedTexts = texts.map(normalizeText);
14771
14846
  const results = new Array(texts.length);
@@ -14799,7 +14874,8 @@ var init_api_provider = __esm({
14799
14874
  const response = await fetchWithRetry(
14800
14875
  `${this.config.baseUrl}/embeddings`,
14801
14876
  this.config.apiKey,
14802
- body
14877
+ body,
14878
+ options2
14803
14879
  );
14804
14880
  this.trackUsage(response);
14805
14881
  for (const item of response.data) {
@@ -14976,9 +15052,9 @@ function wrapProvider(candidate2) {
14976
15052
  return {
14977
15053
  name: candidate2.name,
14978
15054
  dimensions: candidate2.dimensions,
14979
- async embed(text) {
15055
+ async embed(text, options2) {
14980
15056
  try {
14981
- return await candidate2.embed(text);
15057
+ return await candidate2.embed(text, options2);
14982
15058
  } catch (error2) {
14983
15059
  if (kind === "api" && getEmbeddingMode2() === "auto" && isTemporaryEmbeddingFailure(error2)) {
14984
15060
  warnOnce("[memorix] API embedding temporarily unavailable \u2014 switching to local fallback provider");
@@ -14986,7 +15062,7 @@ function wrapProvider(candidate2) {
14986
15062
  if (fallback) {
14987
15063
  provider = wrapProvider(fallback);
14988
15064
  warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);
14989
- return provider.embed(text);
15065
+ return provider.embed(text, options2);
14990
15066
  }
14991
15067
  }
14992
15068
  if (isTemporaryEmbeddingFailure(error2)) {
@@ -14995,9 +15071,9 @@ function wrapProvider(candidate2) {
14995
15071
  throw error2;
14996
15072
  }
14997
15073
  },
14998
- async embedBatch(texts) {
15074
+ async embedBatch(texts, options2) {
14999
15075
  try {
15000
- return await candidate2.embedBatch(texts);
15076
+ return await candidate2.embedBatch(texts, options2);
15001
15077
  } catch (error2) {
15002
15078
  if (kind === "api" && getEmbeddingMode2() === "auto" && isTemporaryEmbeddingFailure(error2)) {
15003
15079
  warnOnce("[memorix] API embedding temporarily unavailable \u2014 switching to local fallback provider");
@@ -15005,7 +15081,7 @@ function wrapProvider(candidate2) {
15005
15081
  if (fallback) {
15006
15082
  provider = wrapProvider(fallback);
15007
15083
  warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);
15008
- return provider.embedBatch(texts);
15084
+ return provider.embedBatch(texts, options2);
15009
15085
  }
15010
15086
  }
15011
15087
  if (isTemporaryEmbeddingFailure(error2)) {
@@ -15061,14 +15137,14 @@ async function getEmbeddingProvider(options2 = {}) {
15061
15137
  return provider;
15062
15138
  }
15063
15139
  if (mode === "api") {
15064
- const initialized = await createAPIProvider();
15140
+ const initialized = await createAPIProvider(options2);
15065
15141
  if (!initialized) return null;
15066
15142
  provider = wrapProvider(initialized);
15067
15143
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
15068
15144
  return provider;
15069
15145
  }
15070
15146
  if (hasAPIEmbeddingConfig()) {
15071
- const initialized = await createAPIProvider();
15147
+ const initialized = await createAPIProvider(options2);
15072
15148
  if (initialized) {
15073
15149
  provider = wrapProvider(initialized);
15074
15150
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
@@ -18967,12 +19043,12 @@ import { createHash as createHash4 } from "crypto";
18967
19043
  function digest(input) {
18968
19044
  return createHash4("sha256").update(input).digest("hex").slice(0, 16);
18969
19045
  }
18970
- function normalizeCodePath(path37) {
18971
- return path37.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
19046
+ function normalizeCodePath(path38) {
19047
+ return path38.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
18972
19048
  }
18973
- function makeCodeFileId(projectId, path37) {
19049
+ function makeCodeFileId(projectId, path38) {
18974
19050
  return `file:${digest(`${projectId}
18975
- ${normalizeCodePath(path37)}`)}`;
19051
+ ${normalizeCodePath(path38)}`)}`;
18976
19052
  }
18977
19053
  function makeCodeSymbolId(input) {
18978
19054
  return `symbol:${digest([
@@ -19446,8 +19522,8 @@ var init_store = __esm({
19446
19522
  });
19447
19523
  tx();
19448
19524
  }
19449
- getFile(projectId, path37) {
19450
- const row = this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? AND path = ?`).get(projectId, normalizeCodePath(path37));
19525
+ getFile(projectId, path38) {
19526
+ const row = this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? AND path = ?`).get(projectId, normalizeCodePath(path38));
19451
19527
  return row ? rowToFile(row) : null;
19452
19528
  }
19453
19529
  listFiles(projectId) {
@@ -19682,30 +19758,30 @@ function normalizeCodeGraphExcludePatterns(exclude) {
19682
19758
  ...(exclude ?? []).map((pattern) => pattern.trim()).filter(Boolean)
19683
19759
  ])];
19684
19760
  }
19685
- function isCodeGraphExcludedPath(path37, exclude) {
19686
- const normalized = normalizeCodePath2(path37);
19761
+ function isCodeGraphExcludedPath(path38, exclude) {
19762
+ const normalized = normalizeCodePath2(path38);
19687
19763
  return normalizeCodeGraphExcludePatterns(exclude).some((pattern) => matchesPattern(normalized, normalizeCodePath2(pattern)));
19688
19764
  }
19689
- function normalizeCodePath2(path37) {
19690
- return path37.replace(/\\/g, "/").replace(/^\.\/+/, "");
19765
+ function normalizeCodePath2(path38) {
19766
+ return path38.replace(/\\/g, "/").replace(/^\.\/+/, "");
19691
19767
  }
19692
- function matchesPattern(path37, pattern) {
19768
+ function matchesPattern(path38, pattern) {
19693
19769
  if (pattern.endsWith("/**")) {
19694
19770
  const base = pattern.slice(0, -3);
19695
19771
  if (base.startsWith("**/")) {
19696
19772
  const suffix = base.slice(3);
19697
- return path37 === suffix || path37.endsWith(`/${suffix}`) || path37.includes(`/${suffix}/`);
19773
+ return path38 === suffix || path38.endsWith(`/${suffix}`) || path38.includes(`/${suffix}/`);
19698
19774
  }
19699
19775
  if (!base.includes("/")) {
19700
- return path37 === base || path37.startsWith(`${base}/`) || path37.includes(`/${base}/`);
19776
+ return path38 === base || path38.startsWith(`${base}/`) || path38.includes(`/${base}/`);
19701
19777
  }
19702
- return path37 === base || path37.startsWith(`${base}/`);
19778
+ return path38 === base || path38.startsWith(`${base}/`);
19703
19779
  }
19704
19780
  if (pattern.startsWith("**/")) {
19705
19781
  const suffix = pattern.slice(3);
19706
- return path37 === suffix || path37.endsWith(`/${suffix}`);
19782
+ return path38 === suffix || path38.endsWith(`/${suffix}`);
19707
19783
  }
19708
- return path37 === pattern || path37.startsWith(`${pattern}/`);
19784
+ return path38 === pattern || path38.startsWith(`${pattern}/`);
19709
19785
  }
19710
19786
  var DEFAULT_CODEGRAPH_EXCLUDES;
19711
19787
  var init_exclude = __esm({
@@ -19750,12 +19826,12 @@ import { join as join5, relative } from "path";
19750
19826
  function hashText(text) {
19751
19827
  return createHash6("sha256").update(text).digest("hex");
19752
19828
  }
19753
- function extension(path37) {
19754
- const index = path37.lastIndexOf(".");
19755
- return index === -1 ? "" : path37.slice(index);
19829
+ function extension(path38) {
19830
+ const index = path38.lastIndexOf(".");
19831
+ return index === -1 ? "" : path38.slice(index);
19756
19832
  }
19757
- function languageForPath(path37) {
19758
- const ext = extension(path37);
19833
+ function languageForPath(path38) {
19834
+ const ext = extension(path38);
19759
19835
  return LANGUAGE_BY_EXTENSION.get(ext) ?? "unknown";
19760
19836
  }
19761
19837
  function resolveMaxFileBytes(value) {
@@ -20236,7 +20312,7 @@ function resolveObservationCodeRefs(obs, lookup) {
20236
20312
  }
20237
20313
  function createStoreLookup(store2, projectId) {
20238
20314
  return {
20239
- findFile: (path37) => store2.getFile(projectId, path37) ?? void 0,
20315
+ findFile: (path38) => store2.getFile(projectId, path38) ?? void 0,
20240
20316
  findSymbols: (names, hintedFileIds) => store2.findSymbolsByNames(projectId, names, hintedFileIds)
20241
20317
  };
20242
20318
  }
@@ -20249,7 +20325,7 @@ function createSnapshotLookup(files, symbols) {
20249
20325
  symbolsByName.set(symbol.name, group);
20250
20326
  }
20251
20327
  return {
20252
- findFile: (path37) => filesByPath.get(normalizeCodePath(path37)),
20328
+ findFile: (path38) => filesByPath.get(normalizeCodePath(path38)),
20253
20329
  findSymbols: (names, hintedFileIds) => {
20254
20330
  const hinted = new Set(hintedFileIds);
20255
20331
  const found = [];
@@ -24448,7 +24524,7 @@ var require_gray_matter = __commonJS({
24448
24524
  "node_modules/gray-matter/index.js"(exports2, module2) {
24449
24525
  "use strict";
24450
24526
  init_esm_shims();
24451
- var fs27 = __require("fs");
24527
+ var fs28 = __require("fs");
24452
24528
  var sections = require_section_matter();
24453
24529
  var defaults = require_defaults();
24454
24530
  var stringify = require_stringify();
@@ -24532,7 +24608,7 @@ var require_gray_matter = __commonJS({
24532
24608
  return stringify(file, data, options2);
24533
24609
  };
24534
24610
  matter12.read = function(filepath, options2) {
24535
- const str2 = fs27.readFileSync(filepath, "utf8");
24611
+ const str2 = fs28.readFileSync(filepath, "utf8");
24536
24612
  const file = matter12(str2, options2);
24537
24613
  file.path = filepath;
24538
24614
  return file;
@@ -25399,8 +25475,8 @@ __export(task_lens_exports, {
25399
25475
  scoreLensSource: () => scoreLensSource,
25400
25476
  shouldShowLensSource: () => shouldShowLensSource
25401
25477
  });
25402
- function normalizePath2(path37) {
25403
- return path37.replace(/\\/g, "/");
25478
+ function normalizePath2(path38) {
25479
+ return path38.replace(/\\/g, "/");
25404
25480
  }
25405
25481
  function tokenize3(text) {
25406
25482
  return (text.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
@@ -25462,8 +25538,8 @@ function isContinuationTask(task) {
25462
25538
  (keyword) => containsTaskKeyword(normalized, keyword)
25463
25539
  );
25464
25540
  }
25465
- function pathKindScore(path37, lens) {
25466
- const normalized = normalizePath2(path37).toLowerCase();
25541
+ function pathKindScore(path38, lens) {
25542
+ const normalized = normalizePath2(path38).toLowerCase();
25467
25543
  const name = normalized.split("/").pop() ?? normalized;
25468
25544
  const inDocs = normalized.startsWith("docs/") || name === "readme.md" || name.includes("readme");
25469
25545
  const isTest = /(^|\/)(tests?|__tests__|spec|fixtures?)\//.test(normalized) || /\.(test|spec)\.[cm]?[jt]sx?$/.test(normalized) || /\.(test|spec)\.py$/.test(normalized);
@@ -25511,8 +25587,8 @@ function sourceTaskMatchScore(source, task) {
25511
25587
  if (matches === 1) return 24;
25512
25588
  return 0;
25513
25589
  }
25514
- function fallbackPathRank(path37) {
25515
- const normalized = normalizePath2(path37);
25590
+ function fallbackPathRank(path38) {
25591
+ const normalized = normalizePath2(path38);
25516
25592
  if (normalized.startsWith("src/")) return 0;
25517
25593
  if (normalized.startsWith("tests/") || normalized.startsWith("test/")) return 1;
25518
25594
  if (normalized.startsWith("packages/") && normalized.includes("/src/")) return 2;
@@ -25521,11 +25597,11 @@ function fallbackPathRank(path37) {
25521
25597
  }
25522
25598
  function rankLensPaths(paths, lens, task) {
25523
25599
  const tokens = tokenize3(task ?? "");
25524
- return [...new Set(paths.map(normalizePath2))].map((path37, index) => ({
25525
- path: path37,
25600
+ return [...new Set(paths.map(normalizePath2))].map((path38, index) => ({
25601
+ path: path38,
25526
25602
  index,
25527
- score: pathKindScore(path37, lens) + tokenScore(path37, tokens),
25528
- fallback: fallbackPathRank(path37)
25603
+ score: pathKindScore(path38, lens) + tokenScore(path38, tokens),
25604
+ fallback: fallbackPathRank(path38)
25529
25605
  })).sort((a3, b3) => b3.score - a3.score || a3.fallback - b3.fallback || a3.index - b3.index || a3.path.localeCompare(b3.path)).map((item) => item.path);
25530
25606
  }
25531
25607
  function lensPathCandidates(lens) {
@@ -32139,6 +32215,827 @@ var init_operator_shared = __esm({
32139
32215
  }
32140
32216
  });
32141
32217
 
32218
+ // src/memory/owner.ts
32219
+ var owner_exports = {};
32220
+ __export(owner_exports, {
32221
+ resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
32222
+ });
32223
+ import { randomUUID as randomUUID9 } from "crypto";
32224
+ import { promises as fs15 } from "fs";
32225
+ import path19 from "path";
32226
+ function ownerPath(dataDir) {
32227
+ const resolved = path19.resolve(dataDir);
32228
+ const home = path19.basename(resolved).toLocaleLowerCase("en-US") === "data" ? path19.dirname(resolved) : resolved;
32229
+ return path19.join(home, "memorix-user.json");
32230
+ }
32231
+ function normalizedOwnerId(value) {
32232
+ const trimmed = value?.trim();
32233
+ return trimmed && ID_PATTERN.test(trimmed) ? trimmed : void 0;
32234
+ }
32235
+ async function readOwnerFile(filePath) {
32236
+ try {
32237
+ const value = JSON.parse(await fs15.readFile(filePath, "utf8"));
32238
+ const id = typeof value.id === "string" ? normalizedOwnerId(value.id) : void 0;
32239
+ return id ? { id, source: "local-file" } : void 0;
32240
+ } catch {
32241
+ return void 0;
32242
+ }
32243
+ }
32244
+ async function resolveLocalMemoryOwner(dataDir, options2 = {}) {
32245
+ const configured = normalizedOwnerId(process.env.MEMORIX_USER_ID);
32246
+ if (configured) return { id: configured, source: "environment" };
32247
+ const filePath = ownerPath(dataDir);
32248
+ const existing = await readOwnerFile(filePath);
32249
+ if (existing || !options2.create) return existing;
32250
+ await fs15.mkdir(path19.dirname(filePath), { recursive: true });
32251
+ const created = {
32252
+ version: 1,
32253
+ id: "local-" + randomUUID9(),
32254
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
32255
+ };
32256
+ try {
32257
+ await fs15.writeFile(filePath, JSON.stringify(created, null, 2) + "\n", { encoding: "utf8", flag: "wx" });
32258
+ return { id: created.id, source: "local-file" };
32259
+ } catch (error2) {
32260
+ if (error2?.code !== "EEXIST") throw error2;
32261
+ const concurrent = await readOwnerFile(filePath);
32262
+ if (concurrent) return concurrent;
32263
+ throw new Error("Memorix could not establish a valid local memory owner identity.");
32264
+ }
32265
+ }
32266
+ var ID_PATTERN;
32267
+ var init_owner = __esm({
32268
+ "src/memory/owner.ts"() {
32269
+ "use strict";
32270
+ init_esm_shims();
32271
+ ID_PATTERN = /^[A-Za-z0-9:_-]{3,160}$/;
32272
+ }
32273
+ });
32274
+
32275
+ // src/memory/long-term-store.ts
32276
+ import { randomUUID as randomUUID10 } from "crypto";
32277
+ function optionalText5(value) {
32278
+ return typeof value === "string" && value.trim() ? value : void 0;
32279
+ }
32280
+ function arrayValue2(value) {
32281
+ if (typeof value !== "string" || !value) return [];
32282
+ try {
32283
+ const parsed = JSON.parse(value);
32284
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
32285
+ } catch {
32286
+ return [];
32287
+ }
32288
+ }
32289
+ function rowToMemory(row) {
32290
+ return {
32291
+ id: row.id,
32292
+ originProjectId: row.originProjectId,
32293
+ ownerId: row.ownerId,
32294
+ scope: row.scope,
32295
+ kind: row.kind,
32296
+ state: row.state,
32297
+ portability: row.portability,
32298
+ title: row.title,
32299
+ content: row.content,
32300
+ facts: arrayValue2(row.factsJson),
32301
+ tags: arrayValue2(row.tagsJson),
32302
+ ...optionalText5(row.applicability) ? { applicability: row.applicability } : {},
32303
+ origin: row.origin,
32304
+ createdAt: row.createdAt,
32305
+ updatedAt: row.updatedAt,
32306
+ ...optionalText5(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
32307
+ ...optionalText5(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
32308
+ ...optionalText5(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
32309
+ ...optionalText5(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
32310
+ ...optionalText5(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
32311
+ accessCount: Number(row.accessCount ?? 0),
32312
+ ...optionalText5(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
32313
+ };
32314
+ }
32315
+ function rowToEvidence2(row) {
32316
+ return {
32317
+ id: row.id,
32318
+ memoryId: row.memoryId,
32319
+ kind: row.kind,
32320
+ referenceId: row.referenceId,
32321
+ relation: row.relation,
32322
+ ...optionalText5(row.locator) ? { locator: row.locator } : {},
32323
+ ...optionalText5(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
32324
+ createdAt: row.createdAt
32325
+ };
32326
+ }
32327
+ function rowToEvent2(row) {
32328
+ return {
32329
+ id: row.id,
32330
+ memoryId: row.memoryId,
32331
+ kind: row.kind,
32332
+ ...optionalText5(row.fromState) ? { fromState: row.fromState } : {},
32333
+ ...optionalText5(row.toState) ? { toState: row.toState } : {},
32334
+ ...optionalText5(row.detail) ? { detail: row.detail } : {},
32335
+ createdAt: row.createdAt
32336
+ };
32337
+ }
32338
+ var LongTermMemoryStore;
32339
+ var init_long_term_store = __esm({
32340
+ "src/memory/long-term-store.ts"() {
32341
+ "use strict";
32342
+ init_esm_shims();
32343
+ init_sqlite_db();
32344
+ LongTermMemoryStore = class {
32345
+ db = null;
32346
+ async init(dataDir) {
32347
+ this.db = getDatabase(dataDir);
32348
+ }
32349
+ transaction(fn) {
32350
+ return this.db.transaction(fn)();
32351
+ }
32352
+ get(id) {
32353
+ const row = this.db.prepare("SELECT * FROM long_term_memories WHERE id = ?").get(id);
32354
+ return row ? rowToMemory(row) : void 0;
32355
+ }
32356
+ list(options2 = {}) {
32357
+ const limit = Math.max(1, Math.min(1e3, Math.floor(options2.limit ?? 500)));
32358
+ const clauses = [];
32359
+ const params = [];
32360
+ if (options2.ownerId) {
32361
+ clauses.push("ownerId = ?");
32362
+ params.push(options2.ownerId);
32363
+ }
32364
+ if (options2.originProjectId) {
32365
+ clauses.push("originProjectId = ?");
32366
+ params.push(options2.originProjectId);
32367
+ }
32368
+ const where = clauses.length ? " WHERE " + clauses.join(" AND ") : "";
32369
+ const rows = this.db.prepare(
32370
+ "SELECT * FROM long_term_memories" + where + " ORDER BY updatedAt DESC, id LIMIT ?"
32371
+ ).all(...params, limit);
32372
+ return rows.map(rowToMemory);
32373
+ }
32374
+ insert(memory) {
32375
+ this.db.prepare(`
32376
+ INSERT INTO long_term_memories (
32377
+ id, originProjectId, ownerId, scope, kind, state, portability,
32378
+ title, content, factsJson, tagsJson, applicability, origin,
32379
+ createdAt, updatedAt, qualifiedAt, approvedAt, archivedAt,
32380
+ supersededBy, lastValidatedAt, accessCount, lastAccessedAt
32381
+ ) VALUES (
32382
+ @id, @originProjectId, @ownerId, @scope, @kind, @state, @portability,
32383
+ @title, @content, @factsJson, @tagsJson, @applicability, @origin,
32384
+ @createdAt, @updatedAt, @qualifiedAt, @approvedAt, @archivedAt,
32385
+ @supersededBy, @lastValidatedAt, @accessCount, @lastAccessedAt
32386
+ )
32387
+ `).run({
32388
+ ...memory,
32389
+ factsJson: JSON.stringify(memory.facts),
32390
+ tagsJson: JSON.stringify(memory.tags),
32391
+ applicability: memory.applicability ?? null,
32392
+ qualifiedAt: memory.qualifiedAt ?? null,
32393
+ approvedAt: memory.approvedAt ?? null,
32394
+ archivedAt: memory.archivedAt ?? null,
32395
+ supersededBy: memory.supersededBy ?? null,
32396
+ lastValidatedAt: memory.lastValidatedAt ?? null,
32397
+ lastAccessedAt: memory.lastAccessedAt ?? null
32398
+ });
32399
+ }
32400
+ update(memory) {
32401
+ this.db.prepare(`
32402
+ UPDATE long_term_memories SET
32403
+ scope = @scope,
32404
+ kind = @kind,
32405
+ state = @state,
32406
+ portability = @portability,
32407
+ title = @title,
32408
+ content = @content,
32409
+ factsJson = @factsJson,
32410
+ tagsJson = @tagsJson,
32411
+ applicability = @applicability,
32412
+ updatedAt = @updatedAt,
32413
+ qualifiedAt = @qualifiedAt,
32414
+ approvedAt = @approvedAt,
32415
+ archivedAt = @archivedAt,
32416
+ supersededBy = @supersededBy,
32417
+ lastValidatedAt = @lastValidatedAt,
32418
+ accessCount = @accessCount,
32419
+ lastAccessedAt = @lastAccessedAt
32420
+ WHERE id = @id
32421
+ `).run({
32422
+ ...memory,
32423
+ factsJson: JSON.stringify(memory.facts),
32424
+ tagsJson: JSON.stringify(memory.tags),
32425
+ applicability: memory.applicability ?? null,
32426
+ qualifiedAt: memory.qualifiedAt ?? null,
32427
+ approvedAt: memory.approvedAt ?? null,
32428
+ archivedAt: memory.archivedAt ?? null,
32429
+ supersededBy: memory.supersededBy ?? null,
32430
+ lastValidatedAt: memory.lastValidatedAt ?? null,
32431
+ lastAccessedAt: memory.lastAccessedAt ?? null
32432
+ });
32433
+ }
32434
+ insertEvidence(input) {
32435
+ const evidence = {
32436
+ id: randomUUID10(),
32437
+ ...input,
32438
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
32439
+ };
32440
+ this.db.prepare(`
32441
+ INSERT INTO long_term_memory_evidence (
32442
+ id, memoryId, kind, referenceId, relation, locator, capturedHash, createdAt
32443
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
32444
+ `).run(
32445
+ evidence.id,
32446
+ evidence.memoryId,
32447
+ evidence.kind,
32448
+ evidence.referenceId,
32449
+ evidence.relation,
32450
+ evidence.locator ?? null,
32451
+ evidence.capturedHash ?? null,
32452
+ evidence.createdAt
32453
+ );
32454
+ return evidence;
32455
+ }
32456
+ listEvidence(memoryId) {
32457
+ return this.db.prepare(`
32458
+ SELECT * FROM long_term_memory_evidence WHERE memoryId = ? ORDER BY createdAt ASC, id
32459
+ `).all(memoryId).map(rowToEvidence2);
32460
+ }
32461
+ recordEvent(input) {
32462
+ const event = {
32463
+ id: randomUUID10(),
32464
+ ...input,
32465
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
32466
+ };
32467
+ this.db.prepare(`
32468
+ INSERT INTO long_term_memory_events (id, memoryId, kind, fromState, toState, detail, createdAt)
32469
+ VALUES (?, ?, ?, ?, ?, ?, ?)
32470
+ `).run(
32471
+ event.id,
32472
+ event.memoryId,
32473
+ event.kind,
32474
+ event.fromState ?? null,
32475
+ event.toState ?? null,
32476
+ event.detail ?? null,
32477
+ event.createdAt
32478
+ );
32479
+ return event;
32480
+ }
32481
+ listEvents(memoryId) {
32482
+ return this.db.prepare(`
32483
+ SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
32484
+ `).all(memoryId).map(rowToEvent2);
32485
+ }
32486
+ markAccess(ids, at = (/* @__PURE__ */ new Date()).toISOString()) {
32487
+ const unique3 = [...new Set(ids.filter(Boolean))];
32488
+ if (unique3.length === 0) return;
32489
+ const statement = this.db.prepare(`
32490
+ UPDATE long_term_memories
32491
+ SET accessCount = accessCount + 1, lastAccessedAt = ?
32492
+ WHERE id = ?
32493
+ `);
32494
+ this.db.transaction(() => {
32495
+ for (const id of unique3) statement.run(at, id);
32496
+ })();
32497
+ }
32498
+ };
32499
+ }
32500
+ });
32501
+
32502
+ // src/memory/long-term-types.ts
32503
+ var LONG_TERM_MEMORY_KINDS, LONG_TERM_MEMORY_SCOPES, LONG_TERM_MEMORY_PORTABILITIES, LONG_TERM_MEMORY_EVIDENCE_KINDS, LONG_TERM_MEMORY_EVIDENCE_RELATIONS;
32504
+ var init_long_term_types = __esm({
32505
+ "src/memory/long-term-types.ts"() {
32506
+ "use strict";
32507
+ init_esm_shims();
32508
+ LONG_TERM_MEMORY_KINDS = ["episodic", "semantic", "procedural"];
32509
+ LONG_TERM_MEMORY_SCOPES = ["project", "user", "team"];
32510
+ LONG_TERM_MEMORY_PORTABILITIES = ["project-bound", "portable"];
32511
+ LONG_TERM_MEMORY_EVIDENCE_KINDS = [
32512
+ "observation",
32513
+ "claim",
32514
+ "workflow",
32515
+ "session",
32516
+ "checkpoint",
32517
+ "git",
32518
+ "code",
32519
+ "test",
32520
+ "run",
32521
+ "document",
32522
+ "manual",
32523
+ "user"
32524
+ ];
32525
+ LONG_TERM_MEMORY_EVIDENCE_RELATIONS = [
32526
+ "supports",
32527
+ "verifies",
32528
+ "derives",
32529
+ "user-confirmed"
32530
+ ];
32531
+ }
32532
+ });
32533
+
32534
+ // src/memory/long-term.ts
32535
+ var long_term_exports = {};
32536
+ __export(long_term_exports, {
32537
+ approveLongTermMemory: () => approveLongTermMemory,
32538
+ archiveLongTermMemory: () => archiveLongTermMemory,
32539
+ canReadLongTermMemory: () => canReadLongTermMemory,
32540
+ createLongTermMemoryCandidate: () => createLongTermMemoryCandidate,
32541
+ createManualLongTermMemory: () => createManualLongTermMemory,
32542
+ getLongTermMemoryDetail: () => getLongTermMemoryDetail,
32543
+ isEligibleLongTermMemory: () => isEligibleLongTermMemory,
32544
+ listLongTermMemories: () => listLongTermMemories,
32545
+ promoteObservationToLongTermMemory: () => promoteObservationToLongTermMemory,
32546
+ qualifyLongTermMemory: () => qualifyLongTermMemory,
32547
+ renderLongTermMemorySummary: () => renderLongTermMemorySummary,
32548
+ selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
32549
+ supersedeLongTermMemory: () => supersedeLongTermMemory
32550
+ });
32551
+ import { randomUUID as randomUUID11 } from "crypto";
32552
+ function isOneOf(value, values) {
32553
+ return typeof value === "string" && values.includes(value);
32554
+ }
32555
+ function compactText2(value, field, max = MAX_TEXT_LENGTH) {
32556
+ if (typeof value !== "string") throw new Error("Long-term memory " + field + " must be text.");
32557
+ const safe = sanitizeCredentials(value).replace(/\s+/g, " ").trim();
32558
+ if (!safe) throw new Error("Long-term memory " + field + " is required.");
32559
+ if (safe.length > max) throw new Error("Long-term memory " + field + " is too long.");
32560
+ return safe;
32561
+ }
32562
+ function compactList(values, field) {
32563
+ if (!values) return [];
32564
+ if (!Array.isArray(values)) throw new Error("Long-term memory " + field + " must be an array.");
32565
+ return [...new Set(values.filter((value) => typeof value === "string").map((value) => compactText2(value, field, 500)))].slice(0, MAX_LIST_ITEMS);
32566
+ }
32567
+ function normalizeEvidence(input) {
32568
+ if (!Array.isArray(input) || input.length === 0) {
32569
+ throw new Error("A long-term memory requires at least one source evidence reference.");
32570
+ }
32571
+ return input.map((evidence) => {
32572
+ if (!evidence || !isOneOf(evidence.kind, LONG_TERM_MEMORY_EVIDENCE_KINDS)) {
32573
+ throw new Error("Long-term memory evidence kind is invalid.");
32574
+ }
32575
+ if (!isOneOf(evidence.relation, LONG_TERM_MEMORY_EVIDENCE_RELATIONS)) {
32576
+ throw new Error("Long-term memory evidence relation is invalid.");
32577
+ }
32578
+ return {
32579
+ kind: evidence.kind,
32580
+ referenceId: compactText2(evidence.referenceId, "evidence reference", 1e3),
32581
+ relation: evidence.relation,
32582
+ ...evidence.locator ? { locator: compactText2(evidence.locator, "evidence locator", 1e3) } : {},
32583
+ ...evidence.capturedHash ? { capturedHash: compactText2(evidence.capturedHash, "evidence hash", 1e3) } : {}
32584
+ };
32585
+ });
32586
+ }
32587
+ function assertScope(scope) {
32588
+ if (!isOneOf(scope, LONG_TERM_MEMORY_SCOPES)) throw new Error("Long-term memory scope is invalid.");
32589
+ }
32590
+ function assertKind(kind) {
32591
+ if (!isOneOf(kind, LONG_TERM_MEMORY_KINDS)) throw new Error("Long-term memory kind is invalid.");
32592
+ }
32593
+ function assertPortability(value) {
32594
+ if (!isOneOf(value, LONG_TERM_MEMORY_PORTABILITIES)) {
32595
+ throw new Error("Long-term memory portability is invalid.");
32596
+ }
32597
+ }
32598
+ function assertPortableEvidence(scope, portability, evidence) {
32599
+ if (portability !== "portable") return;
32600
+ if (scope !== "user") {
32601
+ throw new Error("Only user-scoped long-term memories may be portable across projects.");
32602
+ }
32603
+ if (evidence.some((item) => !PORTABLE_EVIDENCE_KINDS.has(item.kind))) {
32604
+ throw new Error("Portable user memory may only use manual or user-confirmed evidence; project code, Git, observation, test, session, claim, and workflow evidence must remain project-bound.");
32605
+ }
32606
+ }
32607
+ function requireTeamReader(scope, reader) {
32608
+ if (scope === "team" && reader?.isTeamMember !== true) {
32609
+ throw new Error("Team long-term memory requires an explicit active team identity for this project.");
32610
+ }
32611
+ }
32612
+ function matchesScope(memory, reader) {
32613
+ if (memory.scope === "project") return memory.originProjectId === reader.projectId;
32614
+ if (memory.scope === "team") {
32615
+ return memory.originProjectId === reader.projectId && reader.isTeamMember === true;
32616
+ }
32617
+ if (!reader.ownerId || memory.ownerId !== reader.ownerId) return false;
32618
+ return memory.portability === "portable" || memory.originProjectId === reader.projectId;
32619
+ }
32620
+ function canReadLongTermMemory(memory, reader) {
32621
+ return matchesScope(memory, reader);
32622
+ }
32623
+ function isEligibleLongTermMemory(memory) {
32624
+ return memory.state === "qualified" || memory.state === "approved";
32625
+ }
32626
+ function taskTerms(task) {
32627
+ const matches = task.toLocaleLowerCase("en-US").match(/[\p{L}\p{N}_./:-]+/gu) ?? [];
32628
+ return [...new Set(matches.filter((term) => term.length > 1 && !STOP_TERMS.has(term)))].slice(0, 16);
32629
+ }
32630
+ function kindFitScore(kind, task) {
32631
+ const normalized = task.toLocaleLowerCase("en-US");
32632
+ const hints = {
32633
+ episodic: ["resume", "continue", "handoff", "previous", "session", "\u63A5\u624B", "\u7EE7\u7EED", "\u4EA4\u63A5", "\u4E0A\u6B21", "\u4F1A\u8BDD"],
32634
+ semantic: ["why", "what", "architecture", "design", "decision", "reason", "\u4E3A\u4EC0\u4E48", "\u662F\u4EC0\u4E48", "\u67B6\u6784", "\u8BBE\u8BA1", "\u51B3\u7B56", "\u539F\u56E0"],
32635
+ procedural: ["how", "steps", "procedure", "run", "release", "publish", "verify", "implement", "\u6D41\u7A0B", "\u6B65\u9AA4", "\u53D1\u5E03", "\u9A8C\u8BC1", "\u4FEE\u590D", "\u5B9E\u73B0"]
32636
+ };
32637
+ return hints[kind].some((hint) => normalized.includes(hint)) ? 1 : 0;
32638
+ }
32639
+ function validationFreshnessScore(memory) {
32640
+ const validatedAt = memory.lastValidatedAt ?? memory.approvedAt ?? memory.qualifiedAt;
32641
+ if (!validatedAt) return 0;
32642
+ const time3 = Date.parse(validatedAt);
32643
+ if (!Number.isFinite(time3)) return 0;
32644
+ const ageDays = Math.max(0, Date.now() - time3) / (24 * 60 * 60 * 1e3);
32645
+ if (ageDays <= 30) return 0.35;
32646
+ if (ageDays <= 90) return 0.15;
32647
+ return 0;
32648
+ }
32649
+ function scoreForTask(memory, task) {
32650
+ const terms = taskTerms(task);
32651
+ if (terms.length === 0) return void 0;
32652
+ const title = memory.title.toLocaleLowerCase("en-US");
32653
+ const content = memory.content.toLocaleLowerCase("en-US");
32654
+ const facts = memory.facts.join(" ").toLocaleLowerCase("en-US");
32655
+ const tags = memory.tags.join(" ").toLocaleLowerCase("en-US");
32656
+ const applicability = (memory.applicability ?? "").toLocaleLowerCase("en-US");
32657
+ let score = memory.state === "approved" ? 0.5 : 0;
32658
+ const matched = [];
32659
+ for (const term of terms) {
32660
+ let termScore = 0;
32661
+ if (title.includes(term)) termScore += 5;
32662
+ if (tags.includes(term)) termScore += 4;
32663
+ if (applicability.includes(term)) termScore += 3;
32664
+ if (facts.includes(term)) termScore += 2;
32665
+ if (content.includes(term)) termScore += 1;
32666
+ if (termScore > 0) {
32667
+ score += termScore;
32668
+ matched.push(term);
32669
+ }
32670
+ }
32671
+ if (matched.length === 0) return void 0;
32672
+ score += kindFitScore(memory.kind, task);
32673
+ score += validationFreshnessScore(memory);
32674
+ const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
32675
+ const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
32676
+ return { score, reason: kindLabel + " matches " + matched.slice(0, 3).join(", ") + freshness };
32677
+ }
32678
+ function semanticText(memory) {
32679
+ return sanitizeCredentials([
32680
+ memory.title,
32681
+ memory.applicability,
32682
+ memory.tags.join(" "),
32683
+ memory.facts.join(" "),
32684
+ memory.content
32685
+ ].filter((value) => Boolean(value)).join("\n")).replace(/\s+/g, " ").trim().slice(0, MAX_TEXT_LENGTH);
32686
+ }
32687
+ function cosineSimilarity(left, right) {
32688
+ if (left.length === 0 || left.length !== right.length) return 0;
32689
+ let dot = 0;
32690
+ let leftMagnitude = 0;
32691
+ let rightMagnitude = 0;
32692
+ for (let index = 0; index < left.length; index += 1) {
32693
+ const a3 = left[index];
32694
+ const b3 = right[index];
32695
+ if (!Number.isFinite(a3) || !Number.isFinite(b3)) return 0;
32696
+ dot += a3 * b3;
32697
+ leftMagnitude += a3 * a3;
32698
+ rightMagnitude += b3 * b3;
32699
+ }
32700
+ if (leftMagnitude === 0 || rightMagnitude === 0) return 0;
32701
+ return dot / Math.sqrt(leftMagnitude * rightMagnitude);
32702
+ }
32703
+ function semanticSelection(memory, similarity, task) {
32704
+ if (similarity < MIN_SEMANTIC_SIMILARITY) return void 0;
32705
+ const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
32706
+ const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
32707
+ return {
32708
+ score: similarity * 10 + (memory.state === "approved" ? 0.5 : 0) + kindFitScore(memory.kind, task) + validationFreshnessScore(memory),
32709
+ reason: kindLabel + " semantic match " + similarity.toFixed(2) + freshness
32710
+ };
32711
+ }
32712
+ async function resolveSemanticProvider(explicit) {
32713
+ if (explicit !== void 0) return explicit;
32714
+ try {
32715
+ const { getEmbeddingProvider: getEmbeddingProvider2 } = await Promise.resolve().then(() => (init_provider(), provider_exports));
32716
+ return await withTimeout(
32717
+ getEmbeddingProvider2({ requestTimeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS, retry: false }),
32718
+ SEMANTIC_RETRIEVAL_TIMEOUT_MS,
32719
+ "Long-term semantic provider initialization"
32720
+ );
32721
+ } catch {
32722
+ return null;
32723
+ }
32724
+ }
32725
+ function createStore(dataDir) {
32726
+ const store2 = new LongTermMemoryStore();
32727
+ return store2.init(dataDir).then(() => store2);
32728
+ }
32729
+ async function createManualLongTermMemory(input) {
32730
+ const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
32731
+ if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
32732
+ assertScope(input.scope);
32733
+ const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID11(), relation: "supports" }];
32734
+ return createLongTermMemoryWithDataDir({
32735
+ dataDir: input.dataDir,
32736
+ originProjectId: input.projectId,
32737
+ ownerId: owner.id,
32738
+ scope: input.scope,
32739
+ kind: input.kind,
32740
+ portability: input.portability,
32741
+ title: input.title,
32742
+ content: input.content,
32743
+ facts: input.facts,
32744
+ tags: input.tags,
32745
+ applicability: input.applicability,
32746
+ origin: "manual",
32747
+ evidence,
32748
+ reader: input.reader
32749
+ });
32750
+ }
32751
+ async function promoteObservationToLongTermMemory(input) {
32752
+ const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
32753
+ if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
32754
+ return createLongTermMemoryWithDataDir({
32755
+ dataDir: input.dataDir,
32756
+ originProjectId: input.observation.projectId,
32757
+ ownerId: owner.id,
32758
+ scope: input.scope,
32759
+ kind: input.kind,
32760
+ portability: "project-bound",
32761
+ title: input.observation.title,
32762
+ content: input.observation.narrative,
32763
+ facts: input.observation.facts,
32764
+ tags: input.tags ?? input.observation.concepts,
32765
+ applicability: input.applicability,
32766
+ origin: input.observation.source === "git" ? "git" : "agent",
32767
+ evidence: [{
32768
+ kind: "observation",
32769
+ referenceId: "obs:" + input.observation.projectId + ":" + input.observation.id,
32770
+ relation: "derives"
32771
+ }],
32772
+ reader: input.reader
32773
+ });
32774
+ }
32775
+ async function createLongTermMemoryCandidate(input) {
32776
+ return createLongTermMemoryWithDataDir(input);
32777
+ }
32778
+ async function createLongTermMemoryWithDataDir(input) {
32779
+ assertScope(input.scope);
32780
+ assertKind(input.kind);
32781
+ const portability = input.portability ?? "project-bound";
32782
+ assertPortability(portability);
32783
+ requireTeamReader(input.scope, input.reader);
32784
+ const evidenceInputs = normalizeEvidence(input.evidence);
32785
+ assertPortableEvidence(input.scope, portability, evidenceInputs);
32786
+ const now3 = (/* @__PURE__ */ new Date()).toISOString();
32787
+ const memory = {
32788
+ id: randomUUID11(),
32789
+ originProjectId: compactText2(input.originProjectId, "origin project id", 1e3),
32790
+ ownerId: compactText2(input.ownerId, "owner id", 160),
32791
+ scope: input.scope,
32792
+ kind: input.kind,
32793
+ state: "candidate",
32794
+ portability,
32795
+ title: compactText2(input.title, "title", 500),
32796
+ content: compactText2(input.content, "content"),
32797
+ facts: compactList(input.facts, "facts"),
32798
+ tags: compactList(input.tags, "tags"),
32799
+ ...input.applicability ? { applicability: compactText2(input.applicability, "applicability", 1e3) } : {},
32800
+ origin: input.origin ?? "manual",
32801
+ createdAt: now3,
32802
+ updatedAt: now3,
32803
+ accessCount: 0
32804
+ };
32805
+ const store2 = await createStore(input.dataDir);
32806
+ const evidence = store2.transaction(() => {
32807
+ store2.insert(memory);
32808
+ const written = evidenceInputs.map((item) => store2.insertEvidence({ memoryId: memory.id, ...item, createdAt: now3 }));
32809
+ store2.recordEvent({
32810
+ memoryId: memory.id,
32811
+ kind: "created",
32812
+ toState: "candidate",
32813
+ detail: "Created as a source-backed long-term memory candidate.",
32814
+ createdAt: now3
32815
+ });
32816
+ return written;
32817
+ });
32818
+ return { memory, evidence };
32819
+ }
32820
+ function transitionDetail(value) {
32821
+ return compactText2(value, "transition reason", 1e3);
32822
+ }
32823
+ async function transitionMemory(input) {
32824
+ const store2 = await createStore(input.dataDir);
32825
+ return store2.transaction(() => {
32826
+ const current = store2.get(input.id);
32827
+ if (!current) throw new Error("Long-term memory was not found.");
32828
+ if (current.state !== input.expected) {
32829
+ throw new Error("Long-term memory must be " + input.expected + " before it can be " + input.next + ".");
32830
+ }
32831
+ const evidence = store2.listEvidence(current.id);
32832
+ if (evidence.length === 0) throw new Error("Long-term memory cannot advance without source evidence.");
32833
+ const now3 = (/* @__PURE__ */ new Date()).toISOString();
32834
+ const next = {
32835
+ ...current,
32836
+ state: input.next,
32837
+ updatedAt: now3,
32838
+ lastValidatedAt: now3,
32839
+ ...input.next === "qualified" ? { qualifiedAt: now3 } : { approvedAt: now3 }
32840
+ };
32841
+ store2.update(next);
32842
+ store2.recordEvent({
32843
+ memoryId: next.id,
32844
+ kind: input.event,
32845
+ fromState: current.state,
32846
+ toState: next.state,
32847
+ detail: transitionDetail(input.reason),
32848
+ createdAt: now3
32849
+ });
32850
+ return next;
32851
+ });
32852
+ }
32853
+ async function qualifyLongTermMemory(input) {
32854
+ return transitionMemory({ ...input, expected: "candidate", next: "qualified", event: "qualified" });
32855
+ }
32856
+ async function approveLongTermMemory(input) {
32857
+ return transitionMemory({ ...input, expected: "qualified", next: "approved", event: "approved" });
32858
+ }
32859
+ async function archiveLongTermMemory(input) {
32860
+ const store2 = await createStore(input.dataDir);
32861
+ return store2.transaction(() => {
32862
+ const current = store2.get(input.id);
32863
+ if (!current) throw new Error("Long-term memory was not found.");
32864
+ if (current.state === "archived" || current.state === "superseded") {
32865
+ throw new Error("Long-term memory is already inactive.");
32866
+ }
32867
+ const now3 = (/* @__PURE__ */ new Date()).toISOString();
32868
+ const next = { ...current, state: "archived", archivedAt: now3, updatedAt: now3 };
32869
+ store2.update(next);
32870
+ store2.recordEvent({
32871
+ memoryId: next.id,
32872
+ kind: "archived",
32873
+ fromState: current.state,
32874
+ toState: "archived",
32875
+ detail: transitionDetail(input.reason),
32876
+ createdAt: now3
32877
+ });
32878
+ return next;
32879
+ });
32880
+ }
32881
+ async function supersedeLongTermMemory(input) {
32882
+ const store2 = await createStore(input.dataDir);
32883
+ return store2.transaction(() => {
32884
+ const current = store2.get(input.id);
32885
+ if (!current) throw new Error("Long-term memory was not found.");
32886
+ if (current.state === "archived" || current.state === "superseded") {
32887
+ throw new Error("Long-term memory is already inactive.");
32888
+ }
32889
+ if (current.id === input.supersededBy) {
32890
+ throw new Error("Long-term memory cannot supersede itself.");
32891
+ }
32892
+ const replacement = store2.get(input.supersededBy);
32893
+ if (!replacement || !isEligibleLongTermMemory(replacement)) {
32894
+ throw new Error("Replacement long-term memory must be qualified or approved.");
32895
+ }
32896
+ if (replacement.scope !== current.scope) {
32897
+ throw new Error("Replacement long-term memory must use the same scope.");
32898
+ }
32899
+ if (current.scope === "user" && replacement.ownerId !== current.ownerId) {
32900
+ throw new Error("User long-term memory may only be superseded by the same local owner.");
32901
+ }
32902
+ if (current.scope !== "user" && replacement.originProjectId !== current.originProjectId) {
32903
+ throw new Error("Project and team long-term memory may only be superseded within the same project.");
32904
+ }
32905
+ const now3 = (/* @__PURE__ */ new Date()).toISOString();
32906
+ const next = {
32907
+ ...current,
32908
+ state: "superseded",
32909
+ supersededBy: replacement.id,
32910
+ updatedAt: now3
32911
+ };
32912
+ store2.update(next);
32913
+ store2.recordEvent({
32914
+ memoryId: next.id,
32915
+ kind: "superseded",
32916
+ fromState: current.state,
32917
+ toState: "superseded",
32918
+ detail: transitionDetail(input.reason),
32919
+ createdAt: now3
32920
+ });
32921
+ return next;
32922
+ });
32923
+ }
32924
+ async function listLongTermMemories(input) {
32925
+ const store2 = await createStore(input.dataDir);
32926
+ return store2.list({ limit: input.limit ?? 100 }).filter((memory) => canReadLongTermMemory(memory, input.reader)).filter((memory) => input.includeInactive || memory.state !== "archived" && memory.state !== "superseded").map((memory) => ({ memory, evidence: store2.listEvidence(memory.id) }));
32927
+ }
32928
+ async function getLongTermMemoryDetail(input) {
32929
+ const store2 = await createStore(input.dataDir);
32930
+ const memory = store2.get(input.id);
32931
+ if (!memory || !canReadLongTermMemory(memory, input.reader)) {
32932
+ throw new Error("Long-term memory was not found in the active scope.");
32933
+ }
32934
+ store2.markAccess([memory.id]);
32935
+ return { memory, evidence: store2.listEvidence(memory.id), events: store2.listEvents(memory.id) };
32936
+ }
32937
+ async function selectLongTermMemoriesForTask(input) {
32938
+ const task = input.task?.trim();
32939
+ if (!task) return [];
32940
+ const owner = await resolveLocalMemoryOwner(input.dataDir, { create: false });
32941
+ const reader = {
32942
+ projectId: input.projectId,
32943
+ ...owner ? { ownerId: owner.id } : {},
32944
+ ...input.agentId ? { agentId: input.agentId } : {},
32945
+ ...input.isTeamMember ? { isTeamMember: true } : {}
32946
+ };
32947
+ const store2 = await createStore(input.dataDir);
32948
+ const eligible = store2.list({ limit: 1e3 }).filter((memory) => isEligibleLongTermMemory(memory) && canReadLongTermMemory(memory, reader));
32949
+ let selected = eligible.map((memory) => {
32950
+ const ranked = scoreForTask(memory, task);
32951
+ return ranked ? {
32952
+ memory,
32953
+ evidence: store2.listEvidence(memory.id),
32954
+ score: ranked.score,
32955
+ reason: ranked.reason
32956
+ } : void 0;
32957
+ }).filter((item) => Boolean(item)).sort((left, right) => right.score - left.score || right.memory.updatedAt.localeCompare(left.memory.updatedAt) || left.memory.id.localeCompare(right.memory.id));
32958
+ if (selected.length === 0 && eligible.length > 0) {
32959
+ const provider2 = await resolveSemanticProvider(input.embeddingProvider);
32960
+ const candidates = eligible.slice(0, MAX_SEMANTIC_CANDIDATES);
32961
+ if (provider2 && candidates.length > 0) {
32962
+ try {
32963
+ const vectors = await withTimeout(
32964
+ provider2.embedBatch([task, ...candidates.map(semanticText)], {
32965
+ timeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS,
32966
+ retry: false
32967
+ }),
32968
+ SEMANTIC_RETRIEVAL_TIMEOUT_MS,
32969
+ "Long-term semantic retrieval"
32970
+ );
32971
+ const query = vectors[0];
32972
+ if (Array.isArray(query)) {
32973
+ selected = candidates.map((memory, index) => {
32974
+ const vector = vectors[index + 1];
32975
+ const ranked = Array.isArray(vector) ? semanticSelection(memory, cosineSimilarity(query, vector), task) : void 0;
32976
+ return ranked ? {
32977
+ memory,
32978
+ evidence: store2.listEvidence(memory.id),
32979
+ score: ranked.score,
32980
+ reason: ranked.reason
32981
+ } : void 0;
32982
+ }).filter((item) => Boolean(item)).sort((left, right) => right.score - left.score || right.memory.updatedAt.localeCompare(left.memory.updatedAt) || left.memory.id.localeCompare(right.memory.id));
32983
+ }
32984
+ } catch {
32985
+ }
32986
+ }
32987
+ }
32988
+ selected = selected.slice(0, Math.max(1, Math.min(input.limit ?? 3, 5)));
32989
+ store2.markAccess(selected.map((item) => item.memory.id));
32990
+ return selected;
32991
+ }
32992
+ function renderLongTermMemorySummary(memory, maxTokens = 22) {
32993
+ const source = [memory.title, memory.applicability, memory.content].filter(Boolean).join(": ");
32994
+ const safe = sanitizeCredentials(source).replace(/\s+/g, " ").trim();
32995
+ return countTextTokens(safe) <= maxTokens ? safe : truncateToTokenBudget(safe, maxTokens);
32996
+ }
32997
+ var MAX_TEXT_LENGTH, MAX_LIST_ITEMS, MAX_SEMANTIC_CANDIDATES, SEMANTIC_RETRIEVAL_TIMEOUT_MS, MIN_SEMANTIC_SIMILARITY, PORTABLE_EVIDENCE_KINDS, STOP_TERMS;
32998
+ var init_long_term = __esm({
32999
+ "src/memory/long-term.ts"() {
33000
+ "use strict";
33001
+ init_esm_shims();
33002
+ init_token_budget();
33003
+ init_timeout();
33004
+ init_secret_filter();
33005
+ init_owner();
33006
+ init_long_term_store();
33007
+ init_long_term_types();
33008
+ MAX_TEXT_LENGTH = 12e3;
33009
+ MAX_LIST_ITEMS = 40;
33010
+ MAX_SEMANTIC_CANDIDATES = 48;
33011
+ SEMANTIC_RETRIEVAL_TIMEOUT_MS = 1800;
33012
+ MIN_SEMANTIC_SIMILARITY = 0.58;
33013
+ PORTABLE_EVIDENCE_KINDS = /* @__PURE__ */ new Set(["manual", "user"]);
33014
+ STOP_TERMS = /* @__PURE__ */ new Set([
33015
+ "the",
33016
+ "and",
33017
+ "for",
33018
+ "with",
33019
+ "from",
33020
+ "that",
33021
+ "this",
33022
+ "into",
33023
+ "when",
33024
+ "what",
33025
+ "\u5982\u4F55",
33026
+ "\u4EC0\u4E48",
33027
+ "\u8FD9\u4E2A",
33028
+ "\u90A3\u4E2A",
33029
+ "\u6211\u4EEC",
33030
+ "\u9879\u76EE",
33031
+ "\u8FDB\u884C",
33032
+ "\u9700\u8981",
33033
+ "\u7EE7\u7EED",
33034
+ "\u5904\u7406"
33035
+ ]);
33036
+ }
33037
+ });
33038
+
32142
33039
  // src/cli/commands/memory.ts
32143
33040
  var memory_exports = {};
32144
33041
  __export(memory_exports, {
@@ -32151,6 +33048,26 @@ function getStringArg(named, positional) {
32151
33048
  function getIdArg(args, positional) {
32152
33049
  return args.ids || args.id || positional.join(",");
32153
33050
  }
33051
+ function longTermKind(value) {
33052
+ const normalized = (value ?? "semantic").trim().toLowerCase();
33053
+ if (normalized === "episodic" || normalized === "semantic" || normalized === "procedural") return normalized;
33054
+ throw new Error("long-term kind must be episodic, semantic, or procedural.");
33055
+ }
33056
+ function longTermScope(value) {
33057
+ const normalized = (value ?? "project").trim().toLowerCase();
33058
+ if (normalized === "project" || normalized === "user" || normalized === "team") return normalized;
33059
+ throw new Error("long-term scope must be project, user, or team.");
33060
+ }
33061
+ function longTermPortability(value) {
33062
+ const normalized = (value ?? "project-bound").trim().toLowerCase();
33063
+ if (normalized === "project-bound" || normalized === "portable") return normalized;
33064
+ throw new Error("long-term portability must be project-bound or portable.");
33065
+ }
33066
+ function requiredLongTermReason(value) {
33067
+ const reason = value?.trim();
33068
+ if (!reason) throw new Error("reason is required for this long-term memory transition.");
33069
+ return reason;
33070
+ }
32154
33071
  var memory_default;
32155
33072
  var init_memory = __esm({
32156
33073
  "src/cli/commands/memory.ts"() {
@@ -32197,16 +33114,27 @@ var init_memory = __esm({
32197
33114
  instruction: { type: "string", description: "Custom instruction for promoted mini-skills" },
32198
33115
  tags: { type: "string", description: "Comma-separated extra tags for promoted mini-skills" },
32199
33116
  skillId: { type: "string", description: "Mini-skill ID for list/delete actions" },
33117
+ kind: { type: "string", description: "Long-term memory kind: episodic, semantic, or procedural" },
33118
+ scope: { type: "string", description: "Long-term memory scope: project, user, or team" },
33119
+ portability: { type: "string", description: "Long-term memory portability: project-bound or portable" },
33120
+ applicability: { type: "string", description: "When a long-term memory applies" },
33121
+ fromObservation: { type: "string", description: "Observation ID to promote into long-term memory" },
33122
+ supersededBy: { type: "string", description: "Qualified or approved long-term memory that replaces the current record" },
33123
+ "superseded-by": { type: "string", description: "Kebab-case alias for --supersededBy" },
33124
+ reason: { type: "string", description: "Evidence review reason for qualify, approve, or archive" },
33125
+ all: { type: "boolean", description: "Include archived and superseded long-term memories in list output" },
32200
33126
  json: { type: "boolean", description: "Emit machine-readable JSON output" }
32201
33127
  },
32202
33128
  run: async ({ args }) => {
32203
33129
  const action = args._?.[0] || "";
32204
33130
  const positional = (args._ ?? []).slice(1);
33131
+ const longTermAction = action === "long-term" ? (positional[0] || args.action || "list").trim().toLowerCase() : void 0;
32205
33132
  const asJson = !!args.json;
32206
33133
  try {
32207
33134
  const readOnlyActions = /* @__PURE__ */ new Set(["", "search", "graph-context", "recent", "suggest-topic-key", "detail", "timeline"]);
32208
33135
  const needsSearchIndex = action === "search" || action === "detail" || action === "timeline";
32209
- const context = readOnlyActions.has(action) ? await getCliReadContext({ searchIndex: needsSearchIndex }) : await getCliProjectContext({ searchIndex: true });
33136
+ const longTermReadOnly = longTermAction === "list" || longTermAction === "show";
33137
+ const context = readOnlyActions.has(action) || longTermReadOnly ? await getCliReadContext({ searchIndex: needsSearchIndex }) : await getCliProjectContext({ searchIndex: true });
32210
33138
  const { project, dataDir, reader, identity } = context;
32211
33139
  switch (action) {
32212
33140
  case "search": {
@@ -32518,6 +33446,160 @@ var init_memory = __esm({
32518
33446
  );
32519
33447
  return;
32520
33448
  }
33449
+ case "long-term": {
33450
+ const resolvedLongTermAction = longTermAction ?? "list";
33451
+ const longTermPositional = positional.slice(1);
33452
+ const {
33453
+ archiveLongTermMemory: archiveLongTermMemory2,
33454
+ approveLongTermMemory: approveLongTermMemory2,
33455
+ createManualLongTermMemory: createManualLongTermMemory2,
33456
+ getLongTermMemoryDetail: getLongTermMemoryDetail2,
33457
+ listLongTermMemories: listLongTermMemories2,
33458
+ promoteObservationToLongTermMemory: promoteObservationToLongTermMemory2,
33459
+ qualifyLongTermMemory: qualifyLongTermMemory2,
33460
+ supersedeLongTermMemory: supersedeLongTermMemory2
33461
+ } = await Promise.resolve().then(() => (init_long_term(), long_term_exports));
33462
+ const { resolveLocalMemoryOwner: resolveLocalMemoryOwner2 } = await Promise.resolve().then(() => (init_owner(), owner_exports));
33463
+ const owner = await resolveLocalMemoryOwner2(dataDir, { create: false });
33464
+ const longTermReader = {
33465
+ projectId: project.id,
33466
+ ...owner ? { ownerId: owner.id } : {},
33467
+ ...reader.agentId ? { agentId: reader.agentId } : {},
33468
+ ...reader.isTeamMember ? { isTeamMember: true } : {}
33469
+ };
33470
+ const memoryId = () => {
33471
+ const id = args.id?.trim() || args.fromObservation?.trim() || longTermPositional[0]?.trim();
33472
+ if (!id) throw new Error("long-term memory id is required.");
33473
+ return id;
33474
+ };
33475
+ const scope = () => longTermScope(args.scope);
33476
+ const kind = () => longTermKind(args.kind);
33477
+ const portability = () => longTermPortability(args.portability);
33478
+ const reason = () => requiredLongTermReason(args.reason);
33479
+ switch (resolvedLongTermAction) {
33480
+ case "list": {
33481
+ const memories = await listLongTermMemories2({
33482
+ dataDir,
33483
+ reader: longTermReader,
33484
+ includeInactive: !!args.all,
33485
+ limit: parsePositiveInt(args.limit, 50)
33486
+ });
33487
+ emitResult(
33488
+ { project, memories },
33489
+ memories.length === 0 ? "No long-term memories are visible in the active scope." : memories.map((item) => `- ${item.memory.id} [${item.memory.state}/${item.memory.kind}/${item.memory.scope}] ${item.memory.title}`).join("\n"),
33490
+ asJson
33491
+ );
33492
+ return;
33493
+ }
33494
+ case "show": {
33495
+ const detail = await getLongTermMemoryDetail2({ dataDir, id: memoryId(), reader: longTermReader });
33496
+ emitResult(
33497
+ { project, ...detail },
33498
+ [
33499
+ `${detail.memory.id} [${detail.memory.state}/${detail.memory.kind}/${detail.memory.scope}]`,
33500
+ detail.memory.title,
33501
+ detail.memory.content,
33502
+ `Evidence: ${detail.evidence.length}`,
33503
+ `Audit events: ${detail.events.length}`
33504
+ ].join("\n"),
33505
+ asJson
33506
+ );
33507
+ return;
33508
+ }
33509
+ case "add": {
33510
+ const content = getStringArg(args.text, longTermPositional);
33511
+ if (!content) {
33512
+ emitError('text is required for "memorix memory long-term add"', asJson);
33513
+ return;
33514
+ }
33515
+ const result = await createManualLongTermMemory2({
33516
+ dataDir,
33517
+ projectId: project.id,
33518
+ scope: scope(),
33519
+ kind: kind(),
33520
+ title: args.title?.trim() || content.slice(0, 100),
33521
+ content,
33522
+ facts: parseCsvList(args.facts),
33523
+ tags: parseCsvList(args.tags),
33524
+ applicability: args.applicability?.trim(),
33525
+ portability: portability(),
33526
+ reader: longTermReader
33527
+ });
33528
+ emitResult(
33529
+ { project, ...result },
33530
+ `Created long-term memory candidate ${result.memory.id}. Qualify it after checking its evidence.`,
33531
+ asJson
33532
+ );
33533
+ return;
33534
+ }
33535
+ case "promote": {
33536
+ const rawId = args.fromObservation?.trim() || args.id?.trim() || longTermPositional[0]?.trim();
33537
+ const observationId2 = Number.parseInt(rawId || "", 10);
33538
+ if (!Number.isFinite(observationId2)) {
33539
+ emitError('fromObservation or id must be an observation ID for "memorix memory long-term promote"', asJson);
33540
+ return;
33541
+ }
33542
+ const observation = getObservation(observationId2, project.id);
33543
+ if (!observation || !canManageObservation(observation, reader)) {
33544
+ emitError("Observation was not found or is outside the active write scope.", asJson);
33545
+ return;
33546
+ }
33547
+ const result = await promoteObservationToLongTermMemory2({
33548
+ dataDir,
33549
+ observation,
33550
+ scope: scope(),
33551
+ kind: kind(),
33552
+ tags: parseCsvList(args.tags),
33553
+ applicability: args.applicability?.trim(),
33554
+ reader: longTermReader
33555
+ });
33556
+ emitResult(
33557
+ { project, sourceObservationId: observation.id, ...result },
33558
+ `Promoted observation #${observation.id} to long-term memory candidate ${result.memory.id}.`,
33559
+ asJson
33560
+ );
33561
+ return;
33562
+ }
33563
+ case "qualify": {
33564
+ await getLongTermMemoryDetail2({ dataDir, id: memoryId(), reader: longTermReader });
33565
+ const memory = await qualifyLongTermMemory2({ dataDir, id: memoryId(), reason: reason() });
33566
+ emitResult({ project, memory }, `Qualified long-term memory ${memory.id}.`, asJson);
33567
+ return;
33568
+ }
33569
+ case "approve": {
33570
+ await getLongTermMemoryDetail2({ dataDir, id: memoryId(), reader: longTermReader });
33571
+ const memory = await approveLongTermMemory2({ dataDir, id: memoryId(), reason: reason() });
33572
+ emitResult({ project, memory }, `Approved long-term memory ${memory.id}.`, asJson);
33573
+ return;
33574
+ }
33575
+ case "archive": {
33576
+ await getLongTermMemoryDetail2({ dataDir, id: memoryId(), reader: longTermReader });
33577
+ const memory = await archiveLongTermMemory2({ dataDir, id: memoryId(), reason: reason() });
33578
+ emitResult({ project, memory }, `Archived long-term memory ${memory.id}.`, asJson);
33579
+ return;
33580
+ }
33581
+ case "supersede": {
33582
+ const supersededBy = args.supersededBy?.trim() || args["superseded-by"]?.trim();
33583
+ if (!supersededBy) {
33584
+ emitError('supersededBy is required for "memorix memory long-term supersede"', asJson);
33585
+ return;
33586
+ }
33587
+ await getLongTermMemoryDetail2({ dataDir, id: memoryId(), reader: longTermReader });
33588
+ await getLongTermMemoryDetail2({ dataDir, id: supersededBy, reader: longTermReader });
33589
+ const memory = await supersedeLongTermMemory2({
33590
+ dataDir,
33591
+ id: memoryId(),
33592
+ supersededBy,
33593
+ reason: reason()
33594
+ });
33595
+ emitResult({ project, memory }, `Superseded long-term memory ${memory.id} with ${supersededBy}.`, asJson);
33596
+ return;
33597
+ }
33598
+ default:
33599
+ emitError("long-term action must be list, show, add, promote, qualify, approve, archive, or supersede.", asJson);
33600
+ }
33601
+ return;
33602
+ }
32521
33603
  default:
32522
33604
  console.log("Memorix Memory Commands");
32523
33605
  console.log("");
@@ -32533,6 +33615,13 @@ var init_memory = __esm({
32533
33615
  console.log(' memorix memory deduplicate [--query "..."] [--dryRun]');
32534
33616
  console.log(" memorix memory consolidate [--action preview|execute] [--threshold 0.45]");
32535
33617
  console.log(' memorix memory promote --ids 42,43 [--trigger "..."] [--instruction "..."]');
33618
+ console.log(" memorix memory long-term list [--all]");
33619
+ console.log(' memorix memory long-term add --kind semantic --scope user --portability portable --title "..." --text "..." [--tags "..."] [--applicability "..."]');
33620
+ console.log(" memorix memory long-term promote --fromObservation 42 --kind procedural --scope project");
33621
+ console.log(' memorix memory long-term qualify --id <id> --reason "verified against evidence"');
33622
+ console.log(' memorix memory long-term approve --id <id> --reason "reviewed by operator"');
33623
+ console.log(' memorix memory long-term archive --id <id> --reason "no longer current"');
33624
+ console.log(' memorix memory long-term supersede --id <old-id> --superseded-by <qualified-id> --reason "replaced"');
32536
33625
  }
32537
33626
  } catch (error2) {
32538
33627
  emitError(error2 instanceof Error ? error2.message : String(error2), asJson);
@@ -32543,7 +33632,7 @@ var init_memory = __esm({
32543
33632
  });
32544
33633
 
32545
33634
  // src/cli/commands/init-shared.ts
32546
- import path19 from "path";
33635
+ import path20 from "path";
32547
33636
  function resolveInitScope(args, selectedScope) {
32548
33637
  if (args.global && args.project) {
32549
33638
  throw new Error("Choose either --global or --project, not both.");
@@ -32557,7 +33646,7 @@ function resolveInitScope(args, selectedScope) {
32557
33646
  return selectedScope ?? "global";
32558
33647
  }
32559
33648
  function getInitTargetDir(scope, cwd, homeDir) {
32560
- return scope === "global" ? path19.join(homeDir, ".memorix") : cwd;
33649
+ return scope === "global" ? path20.join(homeDir, ".memorix") : cwd;
32561
33650
  }
32562
33651
  function getInitScopeDescription(scope) {
32563
33652
  return scope === "global" ? "Global defaults for all projects on this machine" : "Project-level overrides for the current repository";
@@ -32567,7 +33656,7 @@ function shouldOfferDotenv(scope) {
32567
33656
  }
32568
33657
  function getEnvTemplateTarget(targetDir, options2) {
32569
33658
  const filename = options2.hasDotenvExample ? ".env.memorix-example" : ".env.example";
32570
- return path19.join(targetDir, filename);
33659
+ return path20.join(targetDir, filename);
32571
33660
  }
32572
33661
  function getInitConfigFilename() {
32573
33662
  return "config.toml";
@@ -32590,7 +33679,7 @@ __export(init_exports, {
32590
33679
  });
32591
33680
  import { existsSync as existsSync11, mkdirSync, writeFileSync } from "fs";
32592
33681
  import { homedir as homedir8 } from "os";
32593
- import path20 from "path";
33682
+ import path21 from "path";
32594
33683
  function buildInitTomlConfig(options2) {
32595
33684
  const isGlobal = options2.scope === "global";
32596
33685
  const lines = [
@@ -32724,8 +33813,8 @@ var init_init = __esm({
32724
33813
  }
32725
33814
  const isGlobal = scope === "global";
32726
33815
  const targetDir = getInitTargetDir(scope, process.cwd(), homedir8());
32727
- const targetPath = path20.join(targetDir, isGlobal ? getInitConfigFilename() : getInitProjectConfigFilename());
32728
- const envPath = path20.join(targetDir, ".env");
33816
+ const targetPath = path21.join(targetDir, isGlobal ? getInitConfigFilename() : getInitProjectConfigFilename());
33817
+ const envPath = path21.join(targetDir, ".env");
32729
33818
  v3.info(getInitScopeDescription(scope));
32730
33819
  if (existsSync11(targetPath)) {
32731
33820
  const overwrite = await me({
@@ -32829,7 +33918,7 @@ var init_init = __esm({
32829
33918
  v3.success(`Created ${targetPath}`);
32830
33919
  if (shouldOfferDotenv(scope)) {
32831
33920
  const envExamplePath = getEnvTemplateTarget(targetDir, {
32832
- hasDotenvExample: existsSync11(path20.join(targetDir, ".env.example"))
33921
+ hasDotenvExample: existsSync11(path21.join(targetDir, ".env.example"))
32833
33922
  });
32834
33923
  const envContent = envLines.join("\n");
32835
33924
  if (existsSync11(envExamplePath)) {
@@ -32845,7 +33934,7 @@ var init_init = __esm({
32845
33934
  writeFileSync(envExamplePath, envContent, "utf-8");
32846
33935
  v3.success(`Created ${envExamplePath}`);
32847
33936
  const createEnv = !existsSync11(envPath) ? await me({
32848
- message: `Create .env from ${path20.basename(envExamplePath)} now? (you can fill in keys later)`,
33937
+ message: `Create .env from ${path21.basename(envExamplePath)} now? (you can fill in keys later)`,
32849
33938
  initialValue: true
32850
33939
  }) : false;
32851
33940
  if (!BD(createEnv) && createEnv) {
@@ -34286,15 +35375,15 @@ __export(audit_exports, {
34286
35375
  removeFile: () => removeFile,
34287
35376
  saveAudit: () => saveAudit
34288
35377
  });
34289
- import * as fs15 from "fs/promises";
34290
- import * as path21 from "path";
35378
+ import * as fs16 from "fs/promises";
35379
+ import * as path22 from "path";
34291
35380
  import { homedir as homedir22 } from "os";
34292
35381
  function getAuditFilePath() {
34293
- return process.env.MEMORIX_AUDIT_FILE || path21.join(homedir22(), ".memorix", "audit.json");
35382
+ return process.env.MEMORIX_AUDIT_FILE || path22.join(homedir22(), ".memorix", "audit.json");
34294
35383
  }
34295
35384
  async function loadAudit() {
34296
35385
  try {
34297
- const content = await fs15.readFile(getAuditFilePath(), "utf-8");
35386
+ const content = await fs16.readFile(getAuditFilePath(), "utf-8");
34298
35387
  return JSON.parse(content);
34299
35388
  } catch {
34300
35389
  return {
@@ -34305,9 +35394,9 @@ async function loadAudit() {
34305
35394
  }
34306
35395
  async function saveAudit(data) {
34307
35396
  const auditFile = getAuditFilePath();
34308
- const dir = path21.dirname(auditFile);
34309
- await fs15.mkdir(dir, { recursive: true });
34310
- await fs15.writeFile(auditFile, JSON.stringify(data, null, 2), "utf-8");
35397
+ const dir = path22.dirname(auditFile);
35398
+ await fs16.mkdir(dir, { recursive: true });
35399
+ await fs16.writeFile(auditFile, JSON.stringify(data, null, 2), "utf-8");
34311
35400
  }
34312
35401
  function getProjectId(projectRoot) {
34313
35402
  try {
@@ -34389,8 +35478,8 @@ __export(installers_exports, {
34389
35478
  resolveOpenCodeHookCommand: () => resolveOpenCodeHookCommand,
34390
35479
  uninstallHooks: () => uninstallHooks
34391
35480
  });
34392
- import * as fs16 from "fs/promises";
34393
- import * as path22 from "path";
35481
+ import * as fs17 from "fs/promises";
35482
+ import * as path23 from "path";
34394
35483
  import * as os3 from "os";
34395
35484
  import { execSync as execSync2 } from "child_process";
34396
35485
  function resolveHookCommand() {
@@ -34406,7 +35495,7 @@ function resolveWindowsMemorixShim() {
34406
35495
  stdio: ["ignore", "pipe", "ignore"],
34407
35496
  windowsHide: true
34408
35497
  }));
34409
- return output.split(/\r?\n/).map((candidate2) => candidate2.trim()).find((candidate2) => path22.isAbsolute(candidate2)) ?? null;
35498
+ return output.split(/\r?\n/).map((candidate2) => candidate2.trim()).find((candidate2) => path23.isAbsolute(candidate2)) ?? null;
34410
35499
  } catch {
34411
35500
  return null;
34412
35501
  }
@@ -34601,9 +35690,9 @@ async function installOfficialSkillsForAgent(agent, projectRoot, global2 = false
34601
35690
  const root = global2 ? os3.homedir() : projectRoot;
34602
35691
  const skillPaths = [];
34603
35692
  for (const skillEntry of OFFICIAL_MEMORIX_SKILLS) {
34604
- const skillPath = path22.join(root, relativeDir, skillEntry.name, "SKILL.md");
34605
- await fs16.mkdir(path22.dirname(skillPath), { recursive: true });
34606
- await fs16.writeFile(skillPath, skillEntry.content, "utf-8");
35693
+ const skillPath = path23.join(root, relativeDir, skillEntry.name, "SKILL.md");
35694
+ await fs17.mkdir(path23.dirname(skillPath), { recursive: true });
35695
+ await fs17.writeFile(skillPath, skillEntry.content, "utf-8");
34607
35696
  skillPaths.push(skillPath);
34608
35697
  try {
34609
35698
  const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
@@ -34816,124 +35905,124 @@ async function installOpenCodeSkills(projectRoot, global2 = false) {
34816
35905
  function getProjectConfigPath(agent, projectRoot) {
34817
35906
  switch (agent) {
34818
35907
  case "claude":
34819
- return path22.join(projectRoot, ".claude", "settings.local.json");
35908
+ return path23.join(projectRoot, ".claude", "settings.local.json");
34820
35909
  case "copilot":
34821
- return path22.join(projectRoot, ".github", "hooks", "memorix.json");
35910
+ return path23.join(projectRoot, ".github", "hooks", "memorix.json");
34822
35911
  case "windsurf":
34823
- return path22.join(projectRoot, ".windsurf", "hooks.json");
35912
+ return path23.join(projectRoot, ".windsurf", "hooks.json");
34824
35913
  case "cursor":
34825
- return path22.join(projectRoot, ".cursor", "hooks.json");
35914
+ return path23.join(projectRoot, ".cursor", "hooks.json");
34826
35915
  case "kiro":
34827
- return path22.join(projectRoot, ".kiro", "hooks", "memorix-agent-stop.kiro.hook");
35916
+ return path23.join(projectRoot, ".kiro", "hooks", "memorix-agent-stop.kiro.hook");
34828
35917
  case "codex":
34829
- return path22.join(projectRoot, "AGENTS.md");
35918
+ return path23.join(projectRoot, "AGENTS.md");
34830
35919
  case "trae":
34831
- return path22.join(projectRoot, ".trae", "rules", "project_rules.md");
35920
+ return path23.join(projectRoot, ".trae", "rules", "project_rules.md");
34832
35921
  case "opencode":
34833
- return path22.join(projectRoot, ".opencode", "plugins", "memorix.js");
35922
+ return path23.join(projectRoot, ".opencode", "plugins", "memorix.js");
34834
35923
  case "pi":
34835
- return path22.join(projectRoot, ".pi", "packages", "memorix", "extensions", "memorix.js");
35924
+ return path23.join(projectRoot, ".pi", "packages", "memorix", "extensions", "memorix.js");
34836
35925
  case "openclaw":
34837
- return path22.join(os3.homedir(), ".openclaw", "extensions", "memorix", "hooks", "memorix", "HOOK.md");
35926
+ return path23.join(os3.homedir(), ".openclaw", "extensions", "memorix", "hooks", "memorix", "HOOK.md");
34838
35927
  case "hermes":
34839
- return path22.join(os3.homedir(), ".hermes", "plugins", "memorix", "plugin.yaml");
35928
+ return path23.join(os3.homedir(), ".hermes", "plugins", "memorix", "plugin.yaml");
34840
35929
  case "omp":
34841
- return path22.join(projectRoot, ".omp", "packages", "memorix", "extensions", "memorix.js");
35930
+ return path23.join(projectRoot, ".omp", "packages", "memorix", "extensions", "memorix.js");
34842
35931
  case "antigravity":
34843
- return path22.join(projectRoot, ".agents", "hooks.json");
35932
+ return path23.join(projectRoot, ".agents", "hooks.json");
34844
35933
  case "gemini-cli":
34845
- return path22.join(projectRoot, ".gemini", "settings.json");
35934
+ return path23.join(projectRoot, ".gemini", "settings.json");
34846
35935
  default:
34847
- return path22.join(projectRoot, ".memorix", "hooks.json");
35936
+ return path23.join(projectRoot, ".memorix", "hooks.json");
34848
35937
  }
34849
35938
  }
34850
35939
  function getGlobalConfigPath(agent) {
34851
35940
  const home = os3.homedir();
34852
35941
  switch (agent) {
34853
35942
  case "claude":
34854
- return path22.join(home, ".claude", "settings.json");
35943
+ return path23.join(home, ".claude", "settings.json");
34855
35944
  case "copilot":
34856
35945
  return "";
34857
35946
  case "windsurf":
34858
- return path22.join(home, ".codeium", "windsurf", "hooks.json");
35947
+ return path23.join(home, ".codeium", "windsurf", "hooks.json");
34859
35948
  case "cursor":
34860
- return path22.join(home, ".cursor", "hooks.json");
35949
+ return path23.join(home, ".cursor", "hooks.json");
34861
35950
  case "antigravity":
34862
- return path22.join(home, ".gemini", "config", "hooks.json");
35951
+ return path23.join(home, ".gemini", "config", "hooks.json");
34863
35952
  case "gemini-cli":
34864
- return path22.join(home, ".gemini", "settings.json");
35953
+ return path23.join(home, ".gemini", "settings.json");
34865
35954
  case "opencode":
34866
- return path22.join(home, ".config", "opencode", "plugins", "memorix.js");
35955
+ return path23.join(home, ".config", "opencode", "plugins", "memorix.js");
34867
35956
  case "pi":
34868
- return path22.join(home, ".pi", "agent", "packages", "memorix", "extensions", "memorix.js");
35957
+ return path23.join(home, ".pi", "agent", "packages", "memorix", "extensions", "memorix.js");
34869
35958
  case "openclaw":
34870
- return path22.join(home, ".openclaw", "extensions", "memorix", "hooks", "memorix", "HOOK.md");
35959
+ return path23.join(home, ".openclaw", "extensions", "memorix", "hooks", "memorix", "HOOK.md");
34871
35960
  case "hermes":
34872
- return path22.join(home, ".hermes", "plugins", "memorix", "plugin.yaml");
35961
+ return path23.join(home, ".hermes", "plugins", "memorix", "plugin.yaml");
34873
35962
  case "omp":
34874
- return path22.join(home, ".omp", "agent", "packages", "memorix", "extensions", "memorix.js");
35963
+ return path23.join(home, ".omp", "agent", "packages", "memorix", "extensions", "memorix.js");
34875
35964
  case "trae":
34876
- return path22.join(home, ".trae", "rules", "project_rules.md");
35965
+ return path23.join(home, ".trae", "rules", "project_rules.md");
34877
35966
  default:
34878
- return path22.join(home, ".memorix", "hooks.json");
35967
+ return path23.join(home, ".memorix", "hooks.json");
34879
35968
  }
34880
35969
  }
34881
35970
  function getAgentRulesPath(agent, root, global2 = false) {
34882
35971
  if (global2) {
34883
35972
  switch (agent) {
34884
35973
  case "windsurf":
34885
- return path22.join(root, ".codeium", "windsurf", "rules", "memorix.md");
35974
+ return path23.join(root, ".codeium", "windsurf", "rules", "memorix.md");
34886
35975
  case "cursor":
34887
- return path22.join(root, ".cursor", "rules", "memorix.mdc");
35976
+ return path23.join(root, ".cursor", "rules", "memorix.mdc");
34888
35977
  case "claude":
34889
- return path22.join(root, ".claude", "CLAUDE.md");
35978
+ return path23.join(root, ".claude", "CLAUDE.md");
34890
35979
  case "codex":
34891
- return path22.join(root, ".codex", "AGENTS.md");
35980
+ return path23.join(root, ".codex", "AGENTS.md");
34892
35981
  case "kiro":
34893
- return path22.join(root, ".kiro", "steering", "memorix.md");
35982
+ return path23.join(root, ".kiro", "steering", "memorix.md");
34894
35983
  case "opencode":
34895
- return path22.join(root, ".config", "opencode", "AGENTS.md");
35984
+ return path23.join(root, ".config", "opencode", "AGENTS.md");
34896
35985
  case "antigravity":
34897
35986
  case "gemini-cli":
34898
- return path22.join(root, ".gemini", "GEMINI.md");
35987
+ return path23.join(root, ".gemini", "GEMINI.md");
34899
35988
  case "trae":
34900
- return path22.join(root, ".trae", "rules", "project_rules.md");
35989
+ return path23.join(root, ".trae", "rules", "project_rules.md");
34901
35990
  default:
34902
- return path22.join(root, ".agent", "rules", "memorix.md");
35991
+ return path23.join(root, ".agent", "rules", "memorix.md");
34903
35992
  }
34904
35993
  }
34905
35994
  switch (agent) {
34906
35995
  case "windsurf":
34907
- return path22.join(root, ".windsurf", "rules", "memorix.md");
35996
+ return path23.join(root, ".windsurf", "rules", "memorix.md");
34908
35997
  case "cursor":
34909
- return path22.join(root, ".cursor", "rules", "memorix.mdc");
35998
+ return path23.join(root, ".cursor", "rules", "memorix.mdc");
34910
35999
  case "claude":
34911
- return path22.join(root, "CLAUDE.md");
36000
+ return path23.join(root, "CLAUDE.md");
34912
36001
  case "copilot":
34913
- return path22.join(root, ".github", "copilot-instructions.md");
36002
+ return path23.join(root, ".github", "copilot-instructions.md");
34914
36003
  case "codex":
34915
- return path22.join(root, "AGENTS.md");
36004
+ return path23.join(root, "AGENTS.md");
34916
36005
  case "kiro":
34917
- return path22.join(root, ".kiro", "steering", "memorix.md");
36006
+ return path23.join(root, ".kiro", "steering", "memorix.md");
34918
36007
  case "opencode":
34919
- return path22.join(root, "AGENTS.md");
36008
+ return path23.join(root, "AGENTS.md");
34920
36009
  case "antigravity":
34921
36010
  case "gemini-cli":
34922
- return path22.join(root, "GEMINI.md");
36011
+ return path23.join(root, "GEMINI.md");
34923
36012
  case "trae":
34924
- return path22.join(root, ".trae", "rules", "project_rules.md");
36013
+ return path23.join(root, ".trae", "rules", "project_rules.md");
34925
36014
  default:
34926
- return path22.join(root, ".agent", "rules", "memorix.md");
36015
+ return path23.join(root, ".agent", "rules", "memorix.md");
34927
36016
  }
34928
36017
  }
34929
36018
  async function detectCopilotExtension(home) {
34930
36019
  const extDirs = [
34931
- path22.join(home, ".vscode", "extensions"),
34932
- path22.join(home, ".vscode-insiders", "extensions")
36020
+ path23.join(home, ".vscode", "extensions"),
36021
+ path23.join(home, ".vscode-insiders", "extensions")
34933
36022
  ];
34934
36023
  for (const extDir of extDirs) {
34935
36024
  try {
34936
- const entries = await fs16.readdir(extDir);
36025
+ const entries = await fs17.readdir(extDir);
34937
36026
  if (entries.some((e3) => e3.startsWith("github.copilot-"))) {
34938
36027
  return true;
34939
36028
  }
@@ -34945,21 +36034,21 @@ async function detectCopilotExtension(home) {
34945
36034
  async function detectInstalledAgents() {
34946
36035
  const agents = [];
34947
36036
  const home = os3.homedir();
34948
- const claudeDir = path22.join(home, ".claude");
36037
+ const claudeDir = path23.join(home, ".claude");
34949
36038
  try {
34950
- await fs16.access(claudeDir);
36039
+ await fs17.access(claudeDir);
34951
36040
  agents.push("claude");
34952
36041
  } catch {
34953
36042
  }
34954
- const windsurfDir = path22.join(home, ".codeium", "windsurf");
36043
+ const windsurfDir = path23.join(home, ".codeium", "windsurf");
34955
36044
  try {
34956
- await fs16.access(windsurfDir);
36045
+ await fs17.access(windsurfDir);
34957
36046
  agents.push("windsurf");
34958
36047
  } catch {
34959
36048
  }
34960
- const cursorDir = path22.join(home, ".cursor");
36049
+ const cursorDir = path23.join(home, ".cursor");
34961
36050
  try {
34962
- await fs16.access(cursorDir);
36051
+ await fs17.access(cursorDir);
34963
36052
  agents.push("cursor");
34964
36053
  } catch {
34965
36054
  }
@@ -34967,21 +36056,21 @@ async function detectInstalledAgents() {
34967
36056
  if (copilotDetected) {
34968
36057
  agents.push("copilot");
34969
36058
  }
34970
- const kiroConfig = path22.join(home, ".kiro");
36059
+ const kiroConfig = path23.join(home, ".kiro");
34971
36060
  try {
34972
- await fs16.access(kiroConfig);
36061
+ await fs17.access(kiroConfig);
34973
36062
  agents.push("kiro");
34974
36063
  } catch {
34975
36064
  }
34976
- const codexDir = path22.join(home, ".codex");
36065
+ const codexDir = path23.join(home, ".codex");
34977
36066
  try {
34978
- await fs16.access(codexDir);
36067
+ await fs17.access(codexDir);
34979
36068
  agents.push("codex");
34980
36069
  } catch {
34981
36070
  }
34982
- const antigravityDir = path22.join(home, ".gemini", "config");
36071
+ const antigravityDir = path23.join(home, ".gemini", "config");
34983
36072
  try {
34984
- await fs16.access(antigravityDir);
36073
+ await fs17.access(antigravityDir);
34985
36074
  agents.push("antigravity");
34986
36075
  } catch {
34987
36076
  }
@@ -34992,15 +36081,15 @@ async function detectInstalledAgents() {
34992
36081
  agents.push("gemini-cli");
34993
36082
  } catch {
34994
36083
  }
34995
- const opencodeDir = path22.join(home, ".config", "opencode");
36084
+ const opencodeDir = path23.join(home, ".config", "opencode");
34996
36085
  try {
34997
- await fs16.access(opencodeDir);
36086
+ await fs17.access(opencodeDir);
34998
36087
  agents.push("opencode");
34999
36088
  } catch {
35000
36089
  }
35001
- const traeDir = path22.join(home, ".trae");
36090
+ const traeDir = path23.join(home, ".trae");
35002
36091
  try {
35003
- await fs16.access(traeDir);
36092
+ await fs17.access(traeDir);
35004
36093
  agents.push("trae");
35005
36094
  } catch {
35006
36095
  }
@@ -35034,7 +36123,7 @@ async function installHooks(agent, projectRoot, global2 = false) {
35034
36123
  try {
35035
36124
  const { access: access3, unlink: unlink2 } = await import("fs/promises");
35036
36125
  await access3(entry.path);
35037
- const basename5 = path22.basename(entry.path);
36126
+ const basename5 = path23.basename(entry.path);
35038
36127
  if (basename5 === "AGENTS.md" || basename5 === "GEMINI.md" || basename5 === "CONTEXT.md") {
35039
36128
  continue;
35040
36129
  }
@@ -35089,8 +36178,8 @@ async function installHooks(agent, projectRoot, global2 = false) {
35089
36178
  case "opencode": {
35090
36179
  const pluginContent = generateOpenCodePlugin();
35091
36180
  const pluginPath = global2 ? getGlobalConfigPath(agent) : getProjectConfigPath(agent, projectRoot);
35092
- await fs16.mkdir(path22.dirname(pluginPath), { recursive: true });
35093
- await fs16.writeFile(pluginPath, pluginContent, "utf-8");
36181
+ await fs17.mkdir(path23.dirname(pluginPath), { recursive: true });
36182
+ await fs17.writeFile(pluginPath, pluginContent, "utf-8");
35094
36183
  try {
35095
36184
  const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
35096
36185
  await recordFile2(projectRoot, "hook", pluginPath, agent);
@@ -35119,14 +36208,14 @@ async function installHooks(agent, projectRoot, global2 = false) {
35119
36208
  default:
35120
36209
  generated = generateClaudeConfig();
35121
36210
  }
35122
- await fs16.mkdir(path22.dirname(configPath), { recursive: true });
36211
+ await fs17.mkdir(path23.dirname(configPath), { recursive: true });
35123
36212
  if (agent === "kiro") {
35124
36213
  const hookFiles = generateKiroHookFiles();
35125
- const hooksDir = path22.join(path22.dirname(configPath));
35126
- await fs16.mkdir(hooksDir, { recursive: true });
36214
+ const hooksDir = path23.join(path23.dirname(configPath));
36215
+ await fs17.mkdir(hooksDir, { recursive: true });
35127
36216
  for (const hf of hookFiles) {
35128
- const hookPath = path22.join(hooksDir, hf.filename);
35129
- await fs16.writeFile(hookPath, hf.content, "utf-8");
36217
+ const hookPath = path23.join(hooksDir, hf.filename);
36218
+ await fs17.writeFile(hookPath, hf.content, "utf-8");
35130
36219
  try {
35131
36220
  const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
35132
36221
  await recordFile2(projectRoot, "hook", hookPath, agent);
@@ -35136,7 +36225,7 @@ async function installHooks(agent, projectRoot, global2 = false) {
35136
36225
  } else {
35137
36226
  let existing = {};
35138
36227
  try {
35139
- const content = await fs16.readFile(configPath, "utf-8");
36228
+ const content = await fs17.readFile(configPath, "utf-8");
35140
36229
  existing = JSON.parse(content);
35141
36230
  } catch {
35142
36231
  }
@@ -35171,7 +36260,7 @@ async function installHooks(agent, projectRoot, global2 = false) {
35171
36260
  const h3 = merged.hooks;
35172
36261
  if (h3) delete h3.preToolUse;
35173
36262
  }
35174
- await fs16.writeFile(configPath, JSON.stringify(merged, null, 2), "utf-8");
36263
+ await fs17.writeFile(configPath, JSON.stringify(merged, null, 2), "utf-8");
35175
36264
  try {
35176
36265
  const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
35177
36266
  await recordFile2(projectRoot, "hook", configPath, agent);
@@ -35219,18 +36308,18 @@ async function installAgentRules(agent, projectRoot, global2 = false) {
35219
36308
  const rulesRoot = global2 ? os3.homedir() : projectRoot;
35220
36309
  const rulesPath = getAgentRulesPath(agent, rulesRoot, global2);
35221
36310
  try {
35222
- await fs16.mkdir(path22.dirname(rulesPath), { recursive: true });
36311
+ await fs17.mkdir(path23.dirname(rulesPath), { recursive: true });
35223
36312
  if (agent === "claude" || agent === "codex" || agent === "opencode" || agent === "antigravity" || agent === "gemini-cli") {
35224
36313
  try {
35225
- const existing = await fs16.readFile(rulesPath, "utf-8");
35226
- await fs16.writeFile(rulesPath, mergeMemorixRulesContent(existing, rulesContent), "utf-8");
36314
+ const existing = await fs17.readFile(rulesPath, "utf-8");
36315
+ await fs17.writeFile(rulesPath, mergeMemorixRulesContent(existing, rulesContent), "utf-8");
35227
36316
  try {
35228
36317
  const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
35229
36318
  await recordFile2(projectRoot, "rule", rulesPath, agent);
35230
36319
  } catch {
35231
36320
  }
35232
36321
  } catch {
35233
- await fs16.writeFile(rulesPath, rulesContent, "utf-8");
36322
+ await fs17.writeFile(rulesPath, rulesContent, "utf-8");
35234
36323
  try {
35235
36324
  const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
35236
36325
  await recordFile2(projectRoot, "rule", rulesPath, agent);
@@ -35239,9 +36328,9 @@ async function installAgentRules(agent, projectRoot, global2 = false) {
35239
36328
  }
35240
36329
  } else {
35241
36330
  try {
35242
- await fs16.access(rulesPath);
36331
+ await fs17.access(rulesPath);
35243
36332
  } catch {
35244
- await fs16.writeFile(rulesPath, rulesContent, "utf-8");
36333
+ await fs17.writeFile(rulesPath, rulesContent, "utf-8");
35245
36334
  try {
35246
36335
  const { recordFile: recordFile2 } = await Promise.resolve().then(() => (init_audit(), audit_exports));
35247
36336
  await recordFile2(projectRoot, "rule", rulesPath, agent);
@@ -35331,6 +36420,8 @@ alwaysApply: true
35331
36420
  "- Include `filesModified` when relevant",
35332
36421
  "- Use `topicKey` for topics that evolve over time (prevents duplicates)",
35333
36422
  '- For "why" decisions, use `memorix_store_reasoning`',
36423
+ '- For a stable fact, reusable procedure, or completed episode that merits deliberate long-term review, include `longTerm` in `memorix_store` with the appropriate kind and normally `scope: "project"`. It creates a candidate only: do not use it for routine updates, do not make project-derived evidence portable user memory, and do not assume it enters context until an operator qualifies and approves it through `memorix memory long-term`.',
36424
+ "- A `user` + `portable` durable memory delivered in a task brief is intentionally available across projects. When it matches the task, use it as reusable background even if its origin differs; do not treat it as a current-project fact. Expand it only when needed with `memorix_detail` using its `durable:<id>` reference and a specific purpose.",
35334
36425
  "",
35335
36426
  "**Don't store:** greetings, simple file reads, trivial commands (ls, pwd, git status).",
35336
36427
  "",
@@ -35367,16 +36458,16 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
35367
36458
  let success = false;
35368
36459
  try {
35369
36460
  if (agent === "kiro" || agent === "opencode") {
35370
- await fs16.unlink(configPath);
36461
+ await fs17.unlink(configPath);
35371
36462
  success = true;
35372
36463
  } else {
35373
- const content = await fs16.readFile(configPath, "utf-8");
36464
+ const content = await fs17.readFile(configPath, "utf-8");
35374
36465
  const config2 = JSON.parse(content);
35375
36466
  delete config2.hooks;
35376
36467
  if (Object.keys(config2).length === 0) {
35377
- await fs16.unlink(configPath);
36468
+ await fs17.unlink(configPath);
35378
36469
  } else {
35379
- await fs16.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
36470
+ await fs17.writeFile(configPath, JSON.stringify(config2, null, 2), "utf-8");
35380
36471
  }
35381
36472
  success = true;
35382
36473
  }
@@ -35389,10 +36480,10 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
35389
36480
  const agentFiles = prevFiles.filter((e3) => e3.agent === agent);
35390
36481
  for (const entry of agentFiles) {
35391
36482
  try {
35392
- const basename5 = path22.basename(entry.path);
36483
+ const basename5 = path23.basename(entry.path);
35393
36484
  if (basename5 === "AGENTS.md" || basename5 === "GEMINI.md" || basename5 === "CONTEXT.md") {
35394
36485
  try {
35395
- const content = await fs16.readFile(entry.path, "utf-8");
36486
+ const content = await fs17.readFile(entry.path, "utf-8");
35396
36487
  const memorixStart = content.indexOf("# Memorix");
35397
36488
  if (memorixStart >= 0) {
35398
36489
  const afterMemorix = content.substring(memorixStart);
@@ -35404,9 +36495,9 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
35404
36495
  }
35405
36496
  const cleaned = (before + "\n" + after).trim();
35406
36497
  if (cleaned.length === 0) {
35407
- await fs16.unlink(entry.path);
36498
+ await fs17.unlink(entry.path);
35408
36499
  } else {
35409
- await fs16.writeFile(entry.path, cleaned + "\n", "utf-8");
36500
+ await fs17.writeFile(entry.path, cleaned + "\n", "utf-8");
35410
36501
  }
35411
36502
  }
35412
36503
  } catch {
@@ -35415,7 +36506,7 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
35415
36506
  auditCleaned = true;
35416
36507
  continue;
35417
36508
  }
35418
- await fs16.unlink(entry.path);
36509
+ await fs17.unlink(entry.path);
35419
36510
  await removeFile2(projectRoot, entry.path);
35420
36511
  auditCleaned = true;
35421
36512
  } catch {
@@ -35427,14 +36518,14 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
35427
36518
  if (success) {
35428
36519
  try {
35429
36520
  const { rm: rm2 } = await import("fs/promises");
35430
- const dir = path22.dirname(configPath);
36521
+ const dir = path23.dirname(configPath);
35431
36522
  let current = dir;
35432
36523
  for (let i2 = 0; i2 < 3; i2++) {
35433
36524
  try {
35434
- const entries = await fs16.readdir(current);
36525
+ const entries = await fs17.readdir(current);
35435
36526
  if (entries.length === 0) {
35436
36527
  await rm2(current, { recursive: true });
35437
- current = path22.dirname(current);
36528
+ current = path23.dirname(current);
35438
36529
  } else {
35439
36530
  break;
35440
36531
  }
@@ -35458,12 +36549,12 @@ async function getHookStatus(projectRoot) {
35458
36549
  let usedPath = projectPath;
35459
36550
  const verifiedByDefault = agent !== "opencode" && agent !== "pi";
35460
36551
  try {
35461
- await fs16.access(projectPath);
36552
+ await fs17.access(projectPath);
35462
36553
  installed = true;
35463
36554
  } catch {
35464
36555
  if (globalPath) {
35465
36556
  try {
35466
- await fs16.access(globalPath);
36557
+ await fs17.access(globalPath);
35467
36558
  installed = true;
35468
36559
  usedPath = globalPath;
35469
36560
  } catch {
@@ -35472,7 +36563,7 @@ async function getHookStatus(projectRoot) {
35472
36563
  }
35473
36564
  if (installed && agent === "opencode") {
35474
36565
  try {
35475
- const content = await fs16.readFile(usedPath, "utf-8");
36566
+ const content = await fs17.readFile(usedPath, "utf-8");
35476
36567
  const match = content.match(/@generated-version\s+(\d+)/);
35477
36568
  const installedVersion = match ? parseInt(match[1], 10) : 0;
35478
36569
  outdated = installedVersion < OPENCODE_PLUGIN_VERSION;
@@ -35503,11 +36594,11 @@ var init_installers = __esm({
35503
36594
  init_official_skills();
35504
36595
  OPENCODE_PLUGIN_VERSION = 7;
35505
36596
  AGENT_SKILL_DIRS = {
35506
- cursor: { project: path22.join(".cursor", "skills"), global: path22.join(".cursor", "skills") },
35507
- windsurf: { project: path22.join(".windsurf", "skills"), global: path22.join(".windsurf", "skills") },
35508
- kiro: { project: path22.join(".kiro", "skills"), global: path22.join(".kiro", "skills") },
35509
- opencode: { project: path22.join(".opencode", "skills"), global: path22.join(".config", "opencode", "skills") },
35510
- trae: { project: path22.join(".trae", "skills"), global: path22.join(".trae", "skills") }
36597
+ cursor: { project: path23.join(".cursor", "skills"), global: path23.join(".cursor", "skills") },
36598
+ windsurf: { project: path23.join(".windsurf", "skills"), global: path23.join(".windsurf", "skills") },
36599
+ kiro: { project: path23.join(".kiro", "skills"), global: path23.join(".kiro", "skills") },
36600
+ opencode: { project: path23.join(".opencode", "skills"), global: path23.join(".config", "opencode", "skills") },
36601
+ trae: { project: path23.join(".trae", "skills"), global: path23.join(".trae", "skills") }
35511
36602
  };
35512
36603
  PACKAGE_OWNED_HOOK_AGENTS = /* @__PURE__ */ new Set(["openclaw", "hermes", "omp"]);
35513
36604
  }
@@ -35541,7 +36632,7 @@ import { existsSync as existsSync12 } from "fs";
35541
36632
  import { copyFile, mkdir as mkdir5, readFile as readFile5, readdir as readdir2, rm, writeFile as writeFile5 } from "fs/promises";
35542
36633
  import { createRequire as createRequire5 } from "module";
35543
36634
  import { homedir as homedir24 } from "os";
35544
- import path23 from "path";
36635
+ import path24 from "path";
35545
36636
  import { fileURLToPath as fileURLToPath5 } from "url";
35546
36637
  function getSetupAgentTargets() {
35547
36638
  return [...SUPPORTED_SETUP_AGENTS];
@@ -35578,13 +36669,13 @@ function buildSetupPlan(options2) {
35578
36669
  if (!isPackageOwnedAgent && includeHooks) actions.push("hooks");
35579
36670
  return { agent: options2.agent, mcp, actions, includeHooks, includeRules, includePlugin: wantsPlugin };
35580
36671
  }
35581
- function findPackageRoot(start = path23.dirname(fileURLToPath5(import.meta.url))) {
36672
+ function findPackageRoot(start = path24.dirname(fileURLToPath5(import.meta.url))) {
35582
36673
  let dir = start;
35583
36674
  for (let i2 = 0; i2 < 8; i2++) {
35584
- if (existsSync12(path23.join(dir, "package.json")) && existsSync12(path23.join(dir, "plugins"))) {
36675
+ if (existsSync12(path24.join(dir, "package.json")) && existsSync12(path24.join(dir, "plugins"))) {
35585
36676
  return dir;
35586
36677
  }
35587
- const parent = path23.dirname(dir);
36678
+ const parent = path24.dirname(dir);
35588
36679
  if (parent === dir) break;
35589
36680
  dir = parent;
35590
36681
  }
@@ -35595,12 +36686,12 @@ async function copyDir(source, destination) {
35595
36686
  await mkdir5(destination, { recursive: true });
35596
36687
  const entries = await readdir2(source, { withFileTypes: true });
35597
36688
  for (const entry of entries) {
35598
- const src2 = path23.join(source, entry.name);
35599
- const dest = path23.join(destination, entry.name);
36689
+ const src2 = path24.join(source, entry.name);
36690
+ const dest = path24.join(destination, entry.name);
35600
36691
  if (entry.isDirectory()) {
35601
36692
  await copyDir(src2, dest);
35602
36693
  } else {
35603
- await mkdir5(path23.dirname(dest), { recursive: true });
36694
+ await mkdir5(path24.dirname(dest), { recursive: true });
35604
36695
  await copyFile(src2, dest);
35605
36696
  }
35606
36697
  }
@@ -35608,16 +36699,16 @@ async function copyDir(source, destination) {
35608
36699
  async function writeOfficialSkills(skillsRoot) {
35609
36700
  const written = [];
35610
36701
  for (const skill2 of OFFICIAL_MEMORIX_SKILLS) {
35611
- const skillPath = path23.join(skillsRoot, skill2.name, "SKILL.md");
35612
- await mkdir5(path23.dirname(skillPath), { recursive: true });
36702
+ const skillPath = path24.join(skillsRoot, skill2.name, "SKILL.md");
36703
+ await mkdir5(path24.dirname(skillPath), { recursive: true });
35613
36704
  await writeFile5(skillPath, skill2.content, "utf-8");
35614
36705
  written.push(skillPath);
35615
36706
  }
35616
36707
  return written;
35617
36708
  }
35618
36709
  async function stripHookCaptureFromPlugin(pluginPath, agent) {
35619
- await rm(path23.join(pluginPath, "hooks"), { recursive: true, force: true });
35620
- const manifestPath = agent === "claude" ? path23.join(pluginPath, ".claude-plugin", "plugin.json") : agent === "codex" ? path23.join(pluginPath, ".codex-plugin", "plugin.json") : path23.join(pluginPath, "plugin.json");
36710
+ await rm(path24.join(pluginPath, "hooks"), { recursive: true, force: true });
36711
+ const manifestPath = agent === "claude" ? path24.join(pluginPath, ".claude-plugin", "plugin.json") : agent === "codex" ? path24.join(pluginPath, ".codex-plugin", "plugin.json") : path24.join(pluginPath, "plugin.json");
35621
36712
  try {
35622
36713
  const manifest = JSON.parse(await readFile5(manifestPath, "utf-8"));
35623
36714
  delete manifest.hooks;
@@ -35633,7 +36724,7 @@ async function stripHookCaptureFromPlugin(pluginPath, agent) {
35633
36724
  }
35634
36725
  }
35635
36726
  async function stampCodexPluginVersion(pluginPath) {
35636
- const manifestPath = path23.join(pluginPath, ".codex-plugin", "plugin.json");
36727
+ const manifestPath = path24.join(pluginPath, ".codex-plugin", "plugin.json");
35637
36728
  const manifest = JSON.parse(await readFile5(manifestPath, "utf-8"));
35638
36729
  if (manifest.name !== "memorix") {
35639
36730
  throw new Error(`Unexpected Codex plugin manifest at ${manifestPath}`);
@@ -35643,8 +36734,8 @@ async function stampCodexPluginVersion(pluginPath) {
35643
36734
  `, "utf-8");
35644
36735
  }
35645
36736
  async function stripHookCaptureFromOpenClawBundle(bundlePath) {
35646
- await rm(path23.join(bundlePath, "hooks"), { recursive: true, force: true });
35647
- const manifestPath = path23.join(bundlePath, ".codex-plugin", "plugin.json");
36737
+ await rm(path24.join(bundlePath, "hooks"), { recursive: true, force: true });
36738
+ const manifestPath = path24.join(bundlePath, ".codex-plugin", "plugin.json");
35648
36739
  try {
35649
36740
  const manifest = JSON.parse(await readFile5(manifestPath, "utf-8"));
35650
36741
  delete manifest.hooks;
@@ -35680,7 +36771,7 @@ function mergeHermesPluginEnabled(existingContent, pluginName) {
35680
36771
  }, { lineWidth: -1 });
35681
36772
  }
35682
36773
  function relativePosix(from, to) {
35683
- let rel = path23.relative(from, to).replace(/\\/g, "/");
36774
+ let rel = path24.relative(from, to).replace(/\\/g, "/");
35684
36775
  if (!rel.startsWith("./") && !rel.startsWith("../")) rel = `./${rel}`;
35685
36776
  return rel;
35686
36777
  }
@@ -35818,7 +36909,7 @@ function isOwnedLegacyCodexMcp(content) {
35818
36909
  const server = new CodexMCPAdapter().parse(content).find((entry) => entry.name === "memorix");
35819
36910
  return Boolean(server && isLegacyCodexMemorixNodeServer(server));
35820
36911
  }
35821
- async function removeLegacyCodexMemorixMcpConfig(configPath = path23.join(homedir24(), ".codex", "config.toml")) {
36912
+ async function removeLegacyCodexMemorixMcpConfig(configPath = path24.join(homedir24(), ".codex", "config.toml")) {
35822
36913
  let existingContent;
35823
36914
  try {
35824
36915
  existingContent = await readFile5(configPath, "utf-8");
@@ -35858,12 +36949,12 @@ function isOwnedLegacyCodexHooks(content) {
35858
36949
  }
35859
36950
  }
35860
36951
  async function removeOwnedLegacyCodexPluginFolder(homeDir) {
35861
- const canonicalPath = path23.join(homeDir, "plugins", "memorix");
35862
- const legacyPath = path23.join(homeDir, ".codex", "plugins", "memorix");
36952
+ const canonicalPath = path24.join(homeDir, "plugins", "memorix");
36953
+ const legacyPath = path24.join(homeDir, ".codex", "plugins", "memorix");
35863
36954
  if (!existsSync12(legacyPath)) return "missing";
35864
36955
  if (!existsSync12(canonicalPath)) return "preserved";
35865
36956
  try {
35866
- const manifest = JSON.parse(await readFile5(path23.join(legacyPath, ".codex-plugin", "plugin.json"), "utf-8"));
36957
+ const manifest = JSON.parse(await readFile5(path24.join(legacyPath, ".codex-plugin", "plugin.json"), "utf-8"));
35867
36958
  const repository = String(manifest.repository ?? "");
35868
36959
  if (manifest.name !== "memorix" || !repository.includes("github.com/AVIDS2/memorix")) return "preserved";
35869
36960
  await rm(legacyPath, { recursive: true, force: true });
@@ -35875,7 +36966,7 @@ async function removeOwnedLegacyCodexPluginFolder(homeDir) {
35875
36966
  async function migrateLegacyCodexIntegration(options2 = {}) {
35876
36967
  const homeDir = options2.homeDir ?? homedir24();
35877
36968
  const projectRoot = options2.projectRoot ?? process.cwd();
35878
- const configPath = path23.join(homeDir, ".codex", "config.toml");
36969
+ const configPath = path24.join(homeDir, ".codex", "config.toml");
35879
36970
  let mcp = "missing";
35880
36971
  try {
35881
36972
  const content = await readFile5(configPath, "utf-8");
@@ -35885,7 +36976,7 @@ async function migrateLegacyCodexIntegration(options2 = {}) {
35885
36976
  } catch {
35886
36977
  mcp = "missing";
35887
36978
  }
35888
- const hooksPath = path23.join(projectRoot, ".codex", "hooks.json");
36979
+ const hooksPath = path24.join(projectRoot, ".codex", "hooks.json");
35889
36980
  let projectHooks = "missing";
35890
36981
  try {
35891
36982
  const content = await readFile5(hooksPath, "utf-8");
@@ -35945,12 +37036,12 @@ async function installMcpConfig(options2) {
35945
37036
  }
35946
37037
  const generated = adapter.generate([server]);
35947
37038
  const content = options2.agent === "codex" ? mergeTomlMcpConfig(existingContent, generated) : options2.agent === "hermes" ? mergeYamlMcpConfig(existingContent, generated) : mergeJsonMcpConfig(existingContent, generated);
35948
- await mkdir5(path23.dirname(configPath), { recursive: true });
37039
+ await mkdir5(path24.dirname(configPath), { recursive: true });
35949
37040
  await writeFile5(configPath, content, "utf-8");
35950
37041
  return { agent: options2.agent, configPath, transport: options2.mcp };
35951
37042
  }
35952
37043
  async function upsertCodexMarketplace(marketplacePath, pluginPath) {
35953
- await mkdir5(path23.dirname(marketplacePath), { recursive: true });
37044
+ await mkdir5(path24.dirname(marketplacePath), { recursive: true });
35954
37045
  let catalog;
35955
37046
  try {
35956
37047
  catalog = JSON.parse(await readFile5(marketplacePath, "utf-8"));
@@ -35963,9 +37054,9 @@ async function upsertCodexMarketplace(marketplacePath, pluginPath) {
35963
37054
  plugins: []
35964
37055
  };
35965
37056
  }
35966
- const marketplaceDir = path23.dirname(marketplacePath);
35967
- const agentsDir = path23.dirname(marketplaceDir);
35968
- const marketplaceRoot = path23.basename(agentsDir) === ".agents" ? path23.dirname(agentsDir) : marketplaceDir;
37057
+ const marketplaceDir = path24.dirname(marketplacePath);
37058
+ const agentsDir = path24.dirname(marketplaceDir);
37059
+ const marketplaceRoot = path24.basename(agentsDir) === ".agents" ? path24.dirname(agentsDir) : marketplaceDir;
35969
37060
  const sourcePath = relativePosix(marketplaceRoot, pluginPath);
35970
37061
  const entry = {
35971
37062
  name: "memorix",
@@ -35988,7 +37079,7 @@ async function upsertCodexMarketplace(marketplacePath, pluginPath) {
35988
37079
  await writeFile5(marketplacePath, JSON.stringify(catalog, null, 2) + "\n", "utf-8");
35989
37080
  }
35990
37081
  async function writeClaudeMarketplace(marketplacePath) {
35991
- await mkdir5(path23.dirname(marketplacePath), { recursive: true });
37082
+ await mkdir5(path24.dirname(marketplacePath), { recursive: true });
35992
37083
  const catalog = {
35993
37084
  $schema: "https://anthropic.com/claude-code/marketplace.schema.json",
35994
37085
  name: "memorix-local",
@@ -36017,18 +37108,18 @@ async function writeClaudeMarketplace(marketplacePath) {
36017
37108
  async function installPluginPackage(options2) {
36018
37109
  const home = options2.homeDir ?? homedir24();
36019
37110
  const packageRoot = findPackageRoot();
36020
- const source = path23.join(packageRoot, "plugins", options2.agent, "memorix");
37111
+ const source = path24.join(packageRoot, "plugins", options2.agent, "memorix");
36021
37112
  const includeHooks = options2.includeHooks ?? true;
36022
37113
  if (!existsSync12(source)) {
36023
37114
  throw new Error(`Plugin package template not found: ${source}`);
36024
37115
  }
36025
37116
  if (options2.agent === "codex") {
36026
- const pluginPath2 = path23.join(home, "plugins", "memorix");
36027
- const marketplacePath2 = path23.join(home, ".agents", "plugins", "marketplace.json");
37117
+ const pluginPath2 = path24.join(home, "plugins", "memorix");
37118
+ const marketplacePath2 = path24.join(home, ".agents", "plugins", "marketplace.json");
36028
37119
  await copyDir(source, pluginPath2);
36029
37120
  await stampCodexPluginVersion(pluginPath2);
36030
37121
  if (!includeHooks) await stripHookCaptureFromPlugin(pluginPath2, "codex");
36031
- await writeOfficialSkills(path23.join(pluginPath2, "skills"));
37122
+ await writeOfficialSkills(path24.join(pluginPath2, "skills"));
36032
37123
  await upsertCodexMarketplace(marketplacePath2, pluginPath2);
36033
37124
  return {
36034
37125
  agent: "codex",
@@ -36038,22 +37129,22 @@ async function installPluginPackage(options2) {
36038
37129
  };
36039
37130
  }
36040
37131
  if (options2.agent === "copilot") {
36041
- const pluginPath2 = path23.join(home, ".copilot", "plugins", "local", "memorix");
37132
+ const pluginPath2 = path24.join(home, ".copilot", "plugins", "local", "memorix");
36042
37133
  await copyDir(source, pluginPath2);
36043
37134
  if (!includeHooks) await stripHookCaptureFromPlugin(pluginPath2, "copilot");
36044
- await writeOfficialSkills(path23.join(pluginPath2, "skills"));
37135
+ await writeOfficialSkills(path24.join(pluginPath2, "skills"));
36045
37136
  return {
36046
37137
  agent: "copilot",
36047
37138
  pluginPath: pluginPath2,
36048
37139
  installHint: "Run `copilot plugin install <path>` if automatic install is unavailable, then restart Copilot CLI."
36049
37140
  };
36050
37141
  }
36051
- const marketplaceRoot = path23.join(home, ".claude", "plugins", "marketplaces", "memorix-local");
36052
- const marketplacePath = path23.join(marketplaceRoot, ".claude-plugin", "marketplace.json");
36053
- const pluginPath = path23.join(marketplaceRoot, "plugins", "memorix");
37142
+ const marketplaceRoot = path24.join(home, ".claude", "plugins", "marketplaces", "memorix-local");
37143
+ const marketplacePath = path24.join(marketplaceRoot, ".claude-plugin", "marketplace.json");
37144
+ const pluginPath = path24.join(marketplaceRoot, "plugins", "memorix");
36054
37145
  await copyDir(source, pluginPath);
36055
37146
  if (!includeHooks) await stripHookCaptureFromPlugin(pluginPath, "claude");
36056
- await writeOfficialSkills(path23.join(pluginPath, "skills"));
37147
+ await writeOfficialSkills(path24.join(pluginPath, "skills"));
36057
37148
  await writeClaudeMarketplace(marketplacePath);
36058
37149
  return {
36059
37150
  agent: "claude",
@@ -36066,11 +37157,11 @@ async function installPluginPackage(options2) {
36066
37157
  async function installGeminiExtensionPackage(options2 = {}) {
36067
37158
  const home = options2.homeDir ?? homedir24();
36068
37159
  const packageRoot = findPackageRoot();
36069
- const source = path23.join(packageRoot, "plugins", "gemini", "memorix");
37160
+ const source = path24.join(packageRoot, "plugins", "gemini", "memorix");
36070
37161
  if (!existsSync12(source)) {
36071
37162
  throw new Error(`Gemini extension template not found: ${source}`);
36072
37163
  }
36073
- const extensionPath = path23.join(home, ".gemini", "extensions", "memorix");
37164
+ const extensionPath = path24.join(home, ".gemini", "extensions", "memorix");
36074
37165
  await copyDir(source, extensionPath);
36075
37166
  return {
36076
37167
  agent: "gemini-cli",
@@ -36080,16 +37171,16 @@ async function installGeminiExtensionPackage(options2 = {}) {
36080
37171
  }
36081
37172
  async function installAntigravityPluginPackage(options2 = {}) {
36082
37173
  const packageRoot = findPackageRoot();
36083
- const source = path23.join(packageRoot, "plugins", "antigravity", "memorix");
37174
+ const source = path24.join(packageRoot, "plugins", "antigravity", "memorix");
36084
37175
  if (!existsSync12(source)) {
36085
37176
  throw new Error(`Antigravity plugin template not found: ${source}`);
36086
37177
  }
36087
- const pluginPath = options2.global === false ? path23.join(options2.projectRoot ?? process.cwd(), ".agents", "plugins", "memorix") : path23.join(options2.homeDir ?? homedir24(), ".gemini", "config", "plugins", "memorix");
37178
+ const pluginPath = options2.global === false ? path24.join(options2.projectRoot ?? process.cwd(), ".agents", "plugins", "memorix") : path24.join(options2.homeDir ?? homedir24(), ".gemini", "config", "plugins", "memorix");
36088
37179
  await copyDir(source, pluginPath);
36089
37180
  if (options2.includeHooks === false) {
36090
- await rm(path23.join(pluginPath, "hooks.json"), { force: true });
37181
+ await rm(path24.join(pluginPath, "hooks.json"), { force: true });
36091
37182
  }
36092
- await writeOfficialSkills(path23.join(pluginPath, "skills"));
37183
+ await writeOfficialSkills(path24.join(pluginPath, "skills"));
36093
37184
  return {
36094
37185
  agent: "antigravity",
36095
37186
  pluginPath,
@@ -36098,14 +37189,14 @@ async function installAntigravityPluginPackage(options2 = {}) {
36098
37189
  }
36099
37190
  async function installPiPackage(options2 = {}) {
36100
37191
  const packageRoot = findPackageRoot();
36101
- const source = path23.join(packageRoot, "plugins", "pi", "memorix");
37192
+ const source = path24.join(packageRoot, "plugins", "pi", "memorix");
36102
37193
  if (!existsSync12(source)) {
36103
37194
  throw new Error(`Pi package template not found: ${source}`);
36104
37195
  }
36105
- const defaultRoot = options2.global ? path23.join(options2.homeDir ?? homedir24(), ".pi", "agent", "packages") : path23.join(process.cwd(), ".pi", "packages");
36106
- const packagePath = options2.packageDir ?? path23.join(defaultRoot, "memorix");
37196
+ const defaultRoot = options2.global ? path24.join(options2.homeDir ?? homedir24(), ".pi", "agent", "packages") : path24.join(process.cwd(), ".pi", "packages");
37197
+ const packagePath = options2.packageDir ?? path24.join(defaultRoot, "memorix");
36107
37198
  await copyDir(source, packagePath);
36108
- await writeOfficialSkills(path23.join(packagePath, "skills"));
37199
+ await writeOfficialSkills(path24.join(packagePath, "skills"));
36109
37200
  const installHint = options2.global ? `Setup runs \`pi install "${packagePath}" --approve\`. If Pi is unavailable, run that command after installing Pi.` : `Setup runs \`pi install "${packagePath}" -l --approve\`. If Pi is unavailable, run that command from the project root after installing Pi.`;
36110
37201
  return {
36111
37202
  agent: "pi",
@@ -36116,14 +37207,14 @@ async function installPiPackage(options2 = {}) {
36116
37207
  async function installOpenClawBundlePackage(options2 = {}) {
36117
37208
  const home = options2.homeDir ?? homedir24();
36118
37209
  const packageRoot = findPackageRoot();
36119
- const source = path23.join(packageRoot, "plugins", "openclaw", "memorix");
37210
+ const source = path24.join(packageRoot, "plugins", "openclaw", "memorix");
36120
37211
  if (!existsSync12(source)) {
36121
37212
  throw new Error(`OpenClaw bundle template not found: ${source}`);
36122
37213
  }
36123
- const bundlePath = path23.join(home, ".openclaw", "extensions", "memorix");
37214
+ const bundlePath = path24.join(home, ".openclaw", "extensions", "memorix");
36124
37215
  await copyDir(source, bundlePath);
36125
37216
  if (options2.includeHooks === false) await stripHookCaptureFromOpenClawBundle(bundlePath);
36126
- await writeOfficialSkills(path23.join(bundlePath, "skills"));
37217
+ await writeOfficialSkills(path24.join(bundlePath, "skills"));
36127
37218
  return {
36128
37219
  agent: "openclaw",
36129
37220
  bundlePath,
@@ -36132,22 +37223,22 @@ async function installOpenClawBundlePackage(options2 = {}) {
36132
37223
  }
36133
37224
  async function installHermesPluginPackage(options2 = {}) {
36134
37225
  const packageRoot = findPackageRoot();
36135
- const source = path23.join(packageRoot, "plugins", "hermes", "memorix");
37226
+ const source = path24.join(packageRoot, "plugins", "hermes", "memorix");
36136
37227
  if (!existsSync12(source)) {
36137
37228
  throw new Error(`Hermes plugin template not found: ${source}`);
36138
37229
  }
36139
37230
  const hermesHome = resolveHermesHome(options2.homeDir);
36140
- const pluginPath = path23.join(hermesHome, "plugins", "memorix");
37231
+ const pluginPath = path24.join(hermesHome, "plugins", "memorix");
36141
37232
  await copyDir(source, pluginPath);
36142
- await writeOfficialSkills(path23.join(pluginPath, "skills"));
36143
- const configPath = path23.join(hermesHome, "config.yaml");
37233
+ await writeOfficialSkills(path24.join(pluginPath, "skills"));
37234
+ const configPath = path24.join(hermesHome, "config.yaml");
36144
37235
  let existingContent = null;
36145
37236
  try {
36146
37237
  existingContent = await readFile5(configPath, "utf-8");
36147
37238
  } catch {
36148
37239
  existingContent = null;
36149
37240
  }
36150
- await mkdir5(path23.dirname(configPath), { recursive: true });
37241
+ await mkdir5(path24.dirname(configPath), { recursive: true });
36151
37242
  await writeFile5(configPath, mergeHermesPluginEnabled(existingContent, "memorix"), "utf-8");
36152
37243
  return {
36153
37244
  agent: "hermes",
@@ -36159,14 +37250,14 @@ async function installHermesPluginPackage(options2 = {}) {
36159
37250
  }
36160
37251
  async function installOmpPackage(options2 = {}) {
36161
37252
  const packageRoot = findPackageRoot();
36162
- const source = path23.join(packageRoot, "plugins", "omp", "memorix");
37253
+ const source = path24.join(packageRoot, "plugins", "omp", "memorix");
36163
37254
  if (!existsSync12(source)) {
36164
37255
  throw new Error(`Oh-my-Pi package template not found: ${source}`);
36165
37256
  }
36166
- const defaultRoot = options2.global ? path23.join(options2.homeDir ?? homedir24(), ".omp", "agent", "packages") : path23.join(process.cwd(), ".omp", "packages");
36167
- const packagePath = options2.packageDir ?? path23.join(defaultRoot, "memorix");
37257
+ const defaultRoot = options2.global ? path24.join(options2.homeDir ?? homedir24(), ".omp", "agent", "packages") : path24.join(process.cwd(), ".omp", "packages");
37258
+ const packagePath = options2.packageDir ?? path24.join(defaultRoot, "memorix");
36168
37259
  await copyDir(source, packagePath);
36169
- await writeOfficialSkills(path23.join(packagePath, "skills"));
37260
+ await writeOfficialSkills(path24.join(packagePath, "skills"));
36170
37261
  return {
36171
37262
  agent: "omp",
36172
37263
  packagePath,
@@ -36345,7 +37436,7 @@ ${hook.stdout || ""}`.toLowerCase();
36345
37436
  }
36346
37437
  function resolveHermesCommand(hermesHome) {
36347
37438
  if (process.platform === "win32") {
36348
- const localHermes = path23.join(hermesHome, "hermes-agent", "venv", "Scripts", "hermes.exe");
37439
+ const localHermes = path24.join(hermesHome, "hermes-agent", "venv", "Scripts", "hermes.exe");
36349
37440
  if (existsSync12(localHermes)) return localHermes;
36350
37441
  }
36351
37442
  return "hermes";
@@ -37157,6 +38248,7 @@ function receiptOmissionKind(raw) {
37157
38248
  if (raw.includes("state")) return "code-state";
37158
38249
  if (raw.includes("semantic")) return "semantic-code";
37159
38250
  if (raw.includes("start")) return "start-here";
38251
+ if (raw.includes("durable-memory")) return "durable-memory";
37160
38252
  if (raw.includes("memory")) return "memory";
37161
38253
  if (raw.includes("claim")) return "claim";
37162
38254
  if (raw.includes("knowledge-page")) return "knowledge-page";
@@ -37415,6 +38507,26 @@ function renderTaskWorksetPrompt(input) {
37415
38507
  });
37416
38508
  }
37417
38509
  }
38510
+ if (input.durableMemory.length > 0) {
38511
+ appendLine(lines, "", maxTokens, omitted, "durable-memory-heading");
38512
+ appendLine(lines, "Durable memory", maxTokens, omitted, "durable-memory-heading");
38513
+ for (const memory of input.durableMemory.slice(0, 3)) {
38514
+ appendLine(
38515
+ lines,
38516
+ "- " + memory.kind + " (" + memory.scope + ", " + memory.state + "; ref durable:" + memory.id + "): " + memory.summary,
38517
+ maxTokens,
38518
+ omitted,
38519
+ "durable-memory",
38520
+ selected,
38521
+ {
38522
+ kind: "durable-memory",
38523
+ id: "durable:" + memory.id,
38524
+ reason: memory.reason,
38525
+ trust: "source-backed"
38526
+ }
38527
+ );
38528
+ }
38529
+ }
37418
38530
  if (input.workflows.length > 0) {
37419
38531
  appendLine(lines, "", maxTokens, omitted, "workflow-heading");
37420
38532
  appendLine(lines, "Project workflow", maxTokens, omitted, "workflow-heading");
@@ -37484,6 +38596,32 @@ async function buildTaskWorkset(input) {
37484
38596
  evidenceRefs: evidenceByClaim.get(claim.id).map((item) => item.id),
37485
38597
  reason: selection.reasons[claim.id] ?? "source-qualified task match"
37486
38598
  }));
38599
+ let durableMemory = [];
38600
+ let durableEvidence = [];
38601
+ if (task) {
38602
+ try {
38603
+ const selected = await selectLongTermMemoriesForTask({
38604
+ dataDir: input.dataDir,
38605
+ projectId: input.projectId,
38606
+ task,
38607
+ ...input.reader?.agentId ? { agentId: input.reader.agentId } : {},
38608
+ ...input.reader?.isTeamMember ? { isTeamMember: true } : {},
38609
+ limit: 3
38610
+ });
38611
+ durableMemory = selected.map((item) => ({
38612
+ id: item.memory.id,
38613
+ kind: item.memory.kind,
38614
+ scope: item.memory.scope,
38615
+ state: item.memory.state,
38616
+ title: item.memory.title,
38617
+ summary: renderLongTermMemorySummary(item.memory, 20),
38618
+ evidenceRefs: item.evidence.map((evidence) => evidence.id),
38619
+ reason: item.reason
38620
+ }));
38621
+ durableEvidence = selected.flatMap((item) => item.evidence);
38622
+ } catch {
38623
+ }
38624
+ }
37487
38625
  let workspace;
37488
38626
  let pages = [];
37489
38627
  let workflows = [];
@@ -37523,7 +38661,10 @@ async function buildTaskWorkset(input) {
37523
38661
  const evidenceIds = unique(selection.claims.flatMap((claim) => evidenceIdsForClaim(
37524
38662
  claim,
37525
38663
  evidenceByClaim.get(claim.id) ?? []
37526
- )));
38664
+ )).concat(
38665
+ durableMemory.map((memory) => "durable:" + memory.id),
38666
+ durableEvidence.map((evidence) => "durable-evidence:" + evidence.id)
38667
+ ));
37527
38668
  const verification = unique([
37528
38669
  ...workflows.flatMap((workflow) => workflow.verificationGates),
37529
38670
  ...input.verificationHints
@@ -37549,7 +38690,7 @@ async function buildTaskWorkset(input) {
37549
38690
  } : {}
37550
38691
  } : void 0;
37551
38692
  const base = {
37552
- version: "1.2",
38693
+ version: "1.3",
37553
38694
  task,
37554
38695
  lens: input.lens,
37555
38696
  currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
@@ -37562,6 +38703,7 @@ async function buildTaskWorkset(input) {
37562
38703
  hiddenCautionMemoryCount: input.hiddenCautionMemoryCount ?? 0,
37563
38704
  claims,
37564
38705
  pages,
38706
+ durableMemory,
37565
38707
  workflows,
37566
38708
  cautions: normalizedCautions,
37567
38709
  verification,
@@ -37578,7 +38720,7 @@ async function buildTaskWorkset(input) {
37578
38720
  budget: { maxTokens }
37579
38721
  });
37580
38722
  const receipt = {
37581
- version: "1.2.4",
38723
+ version: "1.3",
37582
38724
  target: input.deliveryTarget ?? "project-context",
37583
38725
  elapsedMs: Math.max(0, Date.now() - startedAt),
37584
38726
  budget: {
@@ -37613,6 +38755,7 @@ var init_workset = __esm({
37613
38755
  init_workspace();
37614
38756
  init_workflow_store();
37615
38757
  init_workflows();
38758
+ init_long_term();
37616
38759
  CONTINUATION_DETAIL_TOKEN_BUDGET = 20;
37617
38760
  }
37618
38761
  });
@@ -37625,7 +38768,7 @@ __export(current_facts_exports, {
37625
38768
  });
37626
38769
  import { execFileSync } from "child_process";
37627
38770
  import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
37628
- import path24 from "path";
38771
+ import path25 from "path";
37629
38772
  function readTextIfExists(filePath) {
37630
38773
  try {
37631
38774
  if (!existsSync13(filePath)) return null;
@@ -37635,7 +38778,7 @@ function readTextIfExists(filePath) {
37635
38778
  }
37636
38779
  }
37637
38780
  function readPackageVersion(rootPath) {
37638
- const text = readTextIfExists(path24.join(rootPath, "package.json"));
38781
+ const text = readTextIfExists(path25.join(rootPath, "package.json"));
37639
38782
  if (!text) return void 0;
37640
38783
  try {
37641
38784
  const parsed = JSON.parse(text);
@@ -37645,7 +38788,7 @@ function readPackageVersion(rootPath) {
37645
38788
  }
37646
38789
  }
37647
38790
  function readLatestChangelog(rootPath) {
37648
- const text = readTextIfExists(path24.join(rootPath, "CHANGELOG.md"));
38791
+ const text = readTextIfExists(path25.join(rootPath, "CHANGELOG.md"));
37649
38792
  if (!text) return void 0;
37650
38793
  const match = text.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
37651
38794
  if (!match) return void 0;
@@ -37715,7 +38858,7 @@ function detectStaleProgressNotes(input) {
37715
38858
  ];
37716
38859
  const notes = [];
37717
38860
  for (const relPath of candidates) {
37718
- const content = readTextIfExists(path24.join(input.rootPath, relPath));
38861
+ const content = readTextIfExists(path25.join(input.rootPath, relPath));
37719
38862
  if (!content) continue;
37720
38863
  const parsed = parseProgressNote(content);
37721
38864
  const olderThanChangelog = compareDateStrings(parsed.lastUpdated, input.latestChangelog?.date);
@@ -37966,9 +39109,9 @@ async function inspectExternalCodeGraph(input) {
37966
39109
  return { health, quality: providerQuality({ mode, health }) };
37967
39110
  }
37968
39111
  function safeRelativePath(projectRoot, value, exclude) {
37969
- const path37 = safeText(value, 1024);
37970
- if (!path37 || isAbsolute2(path37)) return void 0;
37971
- const absolute = resolve3(projectRoot, path37);
39112
+ const path38 = safeText(value, 1024);
39113
+ if (!path38 || isAbsolute2(path38)) return void 0;
39114
+ const absolute = resolve3(projectRoot, path38);
37972
39115
  const fromRoot = relative2(projectRoot, absolute);
37973
39116
  if (!fromRoot || fromRoot === ".." || fromRoot.startsWith("..\\") || fromRoot.startsWith("../") || isAbsolute2(fromRoot)) return void 0;
37974
39117
  const normalized = normalizeCodePath(fromRoot);
@@ -38250,15 +39393,15 @@ function countLanguages(files) {
38250
39393
  }
38251
39394
  return [...counts.entries()].map(([language, files2]) => ({ language, files: files2 })).sort((a3, b3) => a3.language.localeCompare(b3.language));
38252
39395
  }
38253
- function suggestedReadRank(path37) {
38254
- const normalized = path37.replace(/\\/g, "/");
39396
+ function suggestedReadRank(path38) {
39397
+ const normalized = path38.replace(/\\/g, "/");
38255
39398
  if (normalized.startsWith("src/")) return 0;
38256
39399
  if (normalized.startsWith("tests/") || normalized.startsWith("test/")) return 0;
38257
39400
  if (normalized.startsWith("packages/") && normalized.includes("/src/")) return 2;
38258
39401
  return 3;
38259
39402
  }
38260
39403
  function compactSuggestedReads(paths, limit = 8, exclude) {
38261
- return uniq(paths).filter((path37) => !isCodeGraphExcludedPath(path37, exclude)).sort((a3, b3) => suggestedReadRank(a3) - suggestedReadRank(b3)).slice(0, limit);
39404
+ return uniq(paths).filter((path38) => !isCodeGraphExcludedPath(path38, exclude)).sort((a3, b3) => suggestedReadRank(a3) - suggestedReadRank(b3)).slice(0, limit);
38262
39405
  }
38263
39406
  function collectGraph(store2, projectId, observations2, exclude) {
38264
39407
  const files = store2.listFiles(projectId);
@@ -38298,14 +39441,14 @@ function collectGraph(store2, projectId, observations2, exclude) {
38298
39441
  }
38299
39442
  if (files.length === 0) {
38300
39443
  for (const observation of observations2) {
38301
- for (const path37 of observation.filesModified ?? []) {
38302
- if (!path37 || isCodeGraphExcludedPath(path37, exclude)) continue;
38303
- suggestedReads.push(path37);
39444
+ for (const path38 of observation.filesModified ?? []) {
39445
+ if (!path38 || isCodeGraphExcludedPath(path38, exclude)) continue;
39446
+ suggestedReads.push(path38);
38304
39447
  sources.push({
38305
39448
  observationId: observation.id,
38306
39449
  title: observation.title,
38307
39450
  type: observation.type,
38308
- path: path37,
39451
+ path: path38,
38309
39452
  status: "unbound",
38310
39453
  reason: "Recorded file hint; Code Memory refresh is pending."
38311
39454
  });
@@ -38389,7 +39532,7 @@ function formatProjectContextOverview(overview) {
38389
39532
  if (overview.suggestedReads.length === 0) {
38390
39533
  lines.push("- none yet");
38391
39534
  } else {
38392
- overview.suggestedReads.slice(0, 8).forEach((path37, index) => lines.push(`${index + 1}. ${path37}`));
39535
+ overview.suggestedReads.slice(0, 8).forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
38393
39536
  }
38394
39537
  return lines.join("\n");
38395
39538
  }
@@ -38430,8 +39573,8 @@ __export(graph_store_exports, {
38430
39573
  initGraphStore: () => initGraphStore,
38431
39574
  resetGraphStore: () => resetGraphStore
38432
39575
  });
38433
- import path25 from "path";
38434
- import fs17 from "fs";
39576
+ import path26 from "path";
39577
+ import fs18 from "fs";
38435
39578
  function safeJsonParse3(val, fallback) {
38436
39579
  if (val == null || val === "") return fallback;
38437
39580
  try {
@@ -38521,8 +39664,8 @@ var init_graph_store = __esm({
38521
39664
  async migrateFromJsonlIfNeeded() {
38522
39665
  const count3 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM graph_entities`).get();
38523
39666
  if (count3.cnt > 0) return;
38524
- const jsonlPath = path25.join(this.dataDir, "graph.jsonl");
38525
- if (!fs17.existsSync(jsonlPath)) return;
39667
+ const jsonlPath = path26.join(this.dataDir, "graph.jsonl");
39668
+ if (!fs18.existsSync(jsonlPath)) return;
38526
39669
  try {
38527
39670
  const data = await loadGraphJsonl(this.dataDir);
38528
39671
  if (data.entities.length === 0 && data.relations.length === 0) return;
@@ -39264,8 +40407,8 @@ var compaction_checkpoint_store_exports = {};
39264
40407
  __export(compaction_checkpoint_store_exports, {
39265
40408
  CompactionCheckpointStore: () => CompactionCheckpointStore
39266
40409
  });
39267
- import { createHash as createHash12, randomUUID as randomUUID9 } from "crypto";
39268
- function optionalText5(value) {
40410
+ import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
40411
+ function optionalText6(value) {
39269
40412
  return typeof value === "string" && value ? value : void 0;
39270
40413
  }
39271
40414
  function optionalNumber2(value) {
@@ -39319,15 +40462,15 @@ function rowToCheckpoint(row) {
39319
40462
  reason: row.reason,
39320
40463
  sourceEvent: row.source_event,
39321
40464
  sourceKey: row.source_key,
39322
- ...optionalText5(row.summary) ? { summary: row.summary } : {},
40465
+ ...optionalText6(row.summary) ? { summary: row.summary } : {},
39323
40466
  ...optionalNumber2(row.tokens_before) !== void 0 ? { tokensBefore: Number(row.tokens_before) } : {},
39324
- ...optionalText5(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
40467
+ ...optionalText6(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
39325
40468
  ...parseDetails(row.details_json) ? { details: parseDetails(row.details_json) } : {},
39326
40469
  transcriptAvailable: Boolean(row.transcript_available),
39327
40470
  status: row.status,
39328
40471
  preCapturedAt: row.pre_captured_at,
39329
- ...optionalText5(row.completed_at) ? { completedAt: row.completed_at } : {},
39330
- ...optionalText5(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
40472
+ ...optionalText6(row.completed_at) ? { completedAt: row.completed_at } : {},
40473
+ ...optionalText6(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
39331
40474
  deliveryCount: Number(row.delivery_count ?? 0),
39332
40475
  createdAt: row.created_at,
39333
40476
  updatedAt: row.updated_at
@@ -39365,7 +40508,7 @@ var init_compaction_checkpoint_store = __esm({
39365
40508
  if (pending) return rowToCheckpoint(pending);
39366
40509
  const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
39367
40510
  const checkpoint = {
39368
- id: randomUUID9(),
40511
+ id: randomUUID12(),
39369
40512
  projectId: input.projectId,
39370
40513
  sessionId: input.sessionId,
39371
40514
  agent: input.agent,
@@ -39373,7 +40516,7 @@ var init_compaction_checkpoint_store = __esm({
39373
40516
  captureKind: "preflight",
39374
40517
  reason: safeReason(input.reason),
39375
40518
  sourceEvent: input.sourceEvent,
39376
- sourceKey: `pre:${randomUUID9()}`,
40519
+ sourceKey: `pre:${randomUUID12()}`,
39377
40520
  transcriptAvailable: Boolean(input.transcriptAvailable),
39378
40521
  status: "active",
39379
40522
  preCapturedAt: now3,
@@ -39439,7 +40582,7 @@ var init_compaction_checkpoint_store = __esm({
39439
40582
  return this.get(checkpoint2.id);
39440
40583
  }
39441
40584
  const checkpoint = {
39442
- id: randomUUID9(),
40585
+ id: randomUUID12(),
39443
40586
  projectId: input.projectId,
39444
40587
  sessionId: input.sessionId,
39445
40588
  agent: input.agent,
@@ -39574,7 +40717,7 @@ __export(auto_context_exports, {
39574
40717
  formatLegacyAutoProjectContextPrompt: () => formatLegacyAutoProjectContextPrompt
39575
40718
  });
39576
40719
  import { existsSync as existsSync15, statSync as statSync4 } from "fs";
39577
- import path26 from "path";
40720
+ import path27 from "path";
39578
40721
  function activeProjectObservations(observations2, projectId) {
39579
40722
  return observations2.filter((obs) => obs.projectId === projectId && (obs.status ?? "active") === "active");
39580
40723
  }
@@ -39809,6 +40952,7 @@ async function buildAutoProjectContext(input) {
39809
40952
  stale: overview.freshness.stale
39810
40953
  },
39811
40954
  runtimeCautions,
40955
+ ...input.reader ? { reader: input.reader } : {},
39812
40956
  ...input.deliveryTarget ? { deliveryTarget: input.deliveryTarget } : {}
39813
40957
  });
39814
40958
  return {
@@ -39853,7 +40997,7 @@ function dedupeSourcesByObservation(sources) {
39853
40997
  function existingLensCandidates(rootPath, lens) {
39854
40998
  const out = [];
39855
40999
  for (const candidate2 of lensPathCandidates(lens)) {
39856
- const absolute = path26.join(rootPath, candidate2);
41000
+ const absolute = path27.join(rootPath, candidate2);
39857
41001
  try {
39858
41002
  if (!existsSync15(absolute)) continue;
39859
41003
  const stat = statSync4(absolute);
@@ -39963,7 +41107,7 @@ function formatAutoProjectContextSummary(context) {
39963
41107
  "Start here"
39964
41108
  ].filter(Boolean);
39965
41109
  if (startHere.length > 0) {
39966
- startHere.forEach((path37, index) => lines.push(`${index + 1}. ${path37}`));
41110
+ startHere.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
39967
41111
  } else {
39968
41112
  lines.push("- no code-bound reads yet; inspect the task-relevant files directly");
39969
41113
  }
@@ -39972,6 +41116,14 @@ function formatAutoProjectContextSummary(context) {
39972
41116
  "Reliable memory",
39973
41117
  reliableSources.length > 0 ? `- ${reliableSources.length} current code-bound memory link(s)` : "- none yet"
39974
41118
  );
41119
+ if (context.workset.durableMemory.length > 0) {
41120
+ lines.push("", "Durable memory");
41121
+ for (const memory of context.workset.durableMemory.slice(0, 3)) {
41122
+ lines.push(
41123
+ "- " + memory.kind + " (" + memory.scope + ", " + memory.state + "): " + compactContinuationText(memory.summary, 28)
41124
+ );
41125
+ }
41126
+ }
39975
41127
  const continuation = context.workset.continuation;
39976
41128
  if (continuation?.previousSession || continuation?.memories.length || continuation?.compactCheckpoint) {
39977
41129
  lines.push("", "Resume from prior work");
@@ -40021,7 +41173,7 @@ function formatLegacyAutoProjectContextPrompt(context) {
40021
41173
  if (startHere.length === 0) {
40022
41174
  lines.push("- no code-bound reads yet; inspect the task-relevant code directly");
40023
41175
  } else {
40024
- startHere.forEach((path37, index) => lines.push(`${index + 1}. ${path37}`));
41176
+ startHere.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
40025
41177
  }
40026
41178
  const { reliableSources, cautionSources, hiddenReliableCount, hiddenCautionCount } = lensSourceSets(context);
40027
41179
  lines.push("", "Reliable memory");
@@ -40489,6 +41641,7 @@ async function attachTaskWorkset(input) {
40489
41641
  stale: input.pack.warnings.filter((warning) => warning.status === "stale").length
40490
41642
  },
40491
41643
  runtimeCautions: input.runtimeCautions,
41644
+ ...input.reader ? { reader: input.reader } : {},
40492
41645
  deliveryTarget: "context-pack"
40493
41646
  });
40494
41647
  return { ...input.pack, workset };
@@ -40499,7 +41652,7 @@ function buildContextPackPrompt(pack) {
40499
41652
  const unboundMemories = pack.memories.filter((memory) => memory.status === "unbound");
40500
41653
  const lines = ["## Task", pack.task, "", "## Reliable Memories"];
40501
41654
  const visibleCodeFacts = pack.codeFacts.filter((fact) => !isCodeGraphExcludedPath(fact.path)).slice(0, 5);
40502
- const visibleSuggestedReads = pack.suggestedReads.filter((path37) => !isCodeGraphExcludedPath(path37)).slice(0, 5);
41655
+ const visibleSuggestedReads = pack.suggestedReads.filter((path38) => !isCodeGraphExcludedPath(path38)).slice(0, 5);
40503
41656
  if (reliableMemories.length === 0) lines.push("- none");
40504
41657
  for (const memory of reliableMemories) {
40505
41658
  lines.push(`- #${memory.id} ${memory.status}: [${memory.type}] ${memory.title} (${memory.reason})`);
@@ -40523,7 +41676,7 @@ function buildContextPackPrompt(pack) {
40523
41676
  }
40524
41677
  lines.push("", "## Suggested Next Reads");
40525
41678
  if (visibleSuggestedReads.length === 0) lines.push("- none");
40526
- visibleSuggestedReads.forEach((path37, index) => lines.push(`${index + 1}. ${path37}`));
41679
+ visibleSuggestedReads.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
40527
41680
  lines.push("", "## Suggested Verification");
40528
41681
  if (pack.suggestedVerification.length === 0) lines.push("- none");
40529
41682
  for (const command of pack.suggestedVerification) lines.push(`- ${command}`);
@@ -40736,7 +41889,8 @@ ${formatUsageHint()}`;
40736
41889
  } : {},
40737
41890
  ...external.outline ? { semanticCode: external.outline } : {},
40738
41891
  providerQuality: external.quality,
40739
- ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {}
41892
+ ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
41893
+ reader
40740
41894
  });
40741
41895
  emitResult({ project, pack, providerQuality: external.quality }, buildContextPackPrompt(pack), asJson);
40742
41896
  return;
@@ -42922,8 +44076,8 @@ var transfer_exports = {};
42922
44076
  __export(transfer_exports, {
42923
44077
  default: () => transfer_default
42924
44078
  });
42925
- import { promises as fs18 } from "fs";
42926
- import path27 from "path";
44079
+ import { promises as fs19 } from "fs";
44080
+ import path28 from "path";
42927
44081
  async function readStandardInput() {
42928
44082
  return new Promise((resolve6, reject) => {
42929
44083
  let content = "";
@@ -42944,13 +44098,13 @@ async function readImportPayload(args, projectRoot) {
42944
44098
  throw new Error("Choose exactly one import source: --data <json>, --file <path>, or --stdin.");
42945
44099
  }
42946
44100
  if (readFromStdin) return readStandardInput();
42947
- if (file) return fs18.readFile(path27.resolve(projectRoot, file), "utf8");
44101
+ if (file) return fs19.readFile(path28.resolve(projectRoot, file), "utf8");
42948
44102
  return data;
42949
44103
  }
42950
44104
  async function writeExportPayload(projectRoot, output, payload) {
42951
- const outputPath = path27.resolve(projectRoot, output);
42952
- await fs18.mkdir(path27.dirname(outputPath), { recursive: true });
42953
- await fs18.writeFile(outputPath, payload, "utf8");
44105
+ const outputPath = path28.resolve(projectRoot, output);
44106
+ await fs19.mkdir(path28.dirname(outputPath), { recursive: true });
44107
+ await fs19.writeFile(outputPath, payload, "utf8");
42954
44108
  return outputPath;
42955
44109
  }
42956
44110
  var transfer_default;
@@ -44524,8 +45678,8 @@ var init_parseUtil = __esm({
44524
45678
  init_errors2();
44525
45679
  init_en();
44526
45680
  makeIssue = (params) => {
44527
- const { data, path: path37, errorMaps, issueData } = params;
44528
- const fullPath = [...path37, ...issueData.path || []];
45681
+ const { data, path: path38, errorMaps, issueData } = params;
45682
+ const fullPath = [...path38, ...issueData.path || []];
44529
45683
  const fullIssue = {
44530
45684
  ...issueData,
44531
45685
  path: fullPath
@@ -44562,15 +45716,15 @@ var init_parseUtil = __esm({
44562
45716
  this.value = "aborted";
44563
45717
  }
44564
45718
  static mergeArray(status, results) {
44565
- const arrayValue2 = [];
45719
+ const arrayValue3 = [];
44566
45720
  for (const s2 of results) {
44567
45721
  if (s2.status === "aborted")
44568
45722
  return INVALID;
44569
45723
  if (s2.status === "dirty")
44570
45724
  status.dirty();
44571
- arrayValue2.push(s2.value);
45725
+ arrayValue3.push(s2.value);
44572
45726
  }
44573
- return { status: status.value, value: arrayValue2 };
45727
+ return { status: status.value, value: arrayValue3 };
44574
45728
  }
44575
45729
  static async mergeObjectAsync(status, pairs) {
44576
45730
  const syncPairs = [];
@@ -44839,11 +45993,11 @@ var init_types3 = __esm({
44839
45993
  init_parseUtil();
44840
45994
  init_util2();
44841
45995
  ParseInputLazyPath = class {
44842
- constructor(parent, value, path37, key) {
45996
+ constructor(parent, value, path38, key) {
44843
45997
  this._cachedPath = [];
44844
45998
  this.parent = parent;
44845
45999
  this.data = value;
44846
- this._path = path37;
46000
+ this._path = path38;
44847
46001
  this._key = key;
44848
46002
  }
44849
46003
  get path() {
@@ -48596,7 +49750,7 @@ function collectCodeMemory(opts) {
48596
49750
  if (status.indexedAt) lines.push(`Last scan: ${status.indexedAt}`);
48597
49751
  if (suggestedReads.length > 0) {
48598
49752
  lines.push("Suggested reads:");
48599
- suggestedReads.forEach((path37, index) => lines.push(`${index + 1}. ${path37}`));
49753
+ suggestedReads.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
48600
49754
  }
48601
49755
  return lines.join("\n");
48602
49756
  } catch {
@@ -48621,7 +49775,7 @@ __export(planner_exports, {
48621
49775
  materializeTaskGraph: () => materializeTaskGraph,
48622
49776
  seedAutonomousPipeline: () => seedAutonomousPipeline
48623
49777
  });
48624
- import { randomUUID as randomUUID10 } from "crypto";
49778
+ import { randomUUID as randomUUID13 } from "crypto";
48625
49779
  function isPlannerTask(metadata) {
48626
49780
  if (!metadata) return null;
48627
49781
  try {
@@ -48679,7 +49833,7 @@ function seedAutonomousPipeline(teamStore, projectId, config2, opts) {
48679
49833
  const maxIterations = config2.maxIterations ?? 3;
48680
49834
  const taskBudget = config2.taskBudget ?? 15;
48681
49835
  const structuredPlan = opts?.structuredPlan ?? true;
48682
- const pipelineId = randomUUID10();
49836
+ const pipelineId = randomUUID13();
48683
49837
  const meta = {
48684
49838
  plannerType: "plan",
48685
49839
  pipelineId,
@@ -49600,7 +50754,7 @@ __export(receipt_service_exports, {
49600
50754
  });
49601
50755
  import { createHash as createHash13 } from "crypto";
49602
50756
  import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
49603
- import path28 from "path";
50757
+ import path29 from "path";
49604
50758
  function sha256(value) {
49605
50759
  return `sha256:${createHash13("sha256").update(value).digest("hex")}`;
49606
50760
  }
@@ -49629,7 +50783,7 @@ function safeJsonArray(value) {
49629
50783
  }
49630
50784
  }
49631
50785
  async function loadReceiptObservations(dataDir, projectId) {
49632
- const dbPath = path28.join(dataDir, "memorix.db");
50786
+ const dbPath = path29.join(dataDir, "memorix.db");
49633
50787
  if (existsSync18(dbPath)) {
49634
50788
  try {
49635
50789
  const DB = loadBetterSqlite3();
@@ -49646,7 +50800,7 @@ async function loadReceiptObservations(dataDir, projectId) {
49646
50800
  } catch {
49647
50801
  }
49648
50802
  }
49649
- const jsonPath = path28.join(dataDir, "observations.json");
50803
+ const jsonPath = path29.join(dataDir, "observations.json");
49650
50804
  if (!existsSync18(jsonPath)) return [];
49651
50805
  try {
49652
50806
  const parsed = JSON.parse(readFileSync12(jsonPath, "utf-8"));
@@ -50067,10 +51221,10 @@ function assignProp(target, prop, value) {
50067
51221
  configurable: true
50068
51222
  });
50069
51223
  }
50070
- function getElementAtPath(obj, path37) {
50071
- if (!path37)
51224
+ function getElementAtPath(obj, path38) {
51225
+ if (!path38)
50072
51226
  return obj;
50073
- return path37.reduce((acc, key) => acc?.[key], obj);
51227
+ return path38.reduce((acc, key) => acc?.[key], obj);
50074
51228
  }
50075
51229
  function promiseAllObject(promisesObj) {
50076
51230
  const keys = Object.keys(promisesObj);
@@ -50319,11 +51473,11 @@ function aborted(x3, startIndex = 0) {
50319
51473
  }
50320
51474
  return false;
50321
51475
  }
50322
- function prefixIssues(path37, issues) {
51476
+ function prefixIssues(path38, issues) {
50323
51477
  return issues.map((iss) => {
50324
51478
  var _a;
50325
51479
  (_a = iss).path ?? (_a.path = []);
50326
- iss.path.unshift(path37);
51480
+ iss.path.unshift(path38);
50327
51481
  return iss;
50328
51482
  });
50329
51483
  }
@@ -62629,8 +63783,8 @@ var require_utils2 = __commonJS({
62629
63783
  }
62630
63784
  return ind;
62631
63785
  }
62632
- function removeDotSegments(path37) {
62633
- let input = path37;
63786
+ function removeDotSegments(path38) {
63787
+ let input = path38;
62634
63788
  const output = [];
62635
63789
  let nextSlash = -1;
62636
63790
  let len = 0;
@@ -62883,8 +64037,8 @@ var require_schemes = __commonJS({
62883
64037
  wsComponent.secure = void 0;
62884
64038
  }
62885
64039
  if (wsComponent.resourceName) {
62886
- const [path37, query] = wsComponent.resourceName.split("?");
62887
- wsComponent.path = path37 && path37 !== "/" ? path37 : void 0;
64040
+ const [path38, query] = wsComponent.resourceName.split("?");
64041
+ wsComponent.path = path38 && path38 !== "/" ? path38 : void 0;
62888
64042
  wsComponent.query = query;
62889
64043
  wsComponent.resourceName = void 0;
62890
64044
  }
@@ -66323,12 +67477,12 @@ var require_dist = __commonJS({
66323
67477
  throw new Error(`Unknown format "${name}"`);
66324
67478
  return f4;
66325
67479
  };
66326
- function addFormats(ajv, list, fs27, exportName) {
67480
+ function addFormats(ajv, list, fs28, exportName) {
66327
67481
  var _a;
66328
67482
  var _b;
66329
67483
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
66330
67484
  for (const f4 of list)
66331
- ajv.addFormat(f4, fs27[f4]);
67485
+ ajv.addFormat(f4, fs28[f4]);
66332
67486
  }
66333
67487
  module2.exports = exports2 = formatsPlugin;
66334
67488
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -68804,8 +69958,8 @@ var syncer_exports = {};
68804
69958
  __export(syncer_exports, {
68805
69959
  RulesSyncer: () => RulesSyncer
68806
69960
  });
68807
- import { promises as fs19 } from "fs";
68808
- import path29 from "path";
69961
+ import { promises as fs20 } from "fs";
69962
+ import path30 from "path";
68809
69963
  var RulesSyncer;
68810
69964
  var init_syncer = __esm({
68811
69965
  "src/rules/syncer.ts"() {
@@ -68850,8 +70004,8 @@ var init_syncer = __esm({
68850
70004
  const found = await this.findFiles(scanPath);
68851
70005
  for (const filePath of found) {
68852
70006
  try {
68853
- const content = await fs19.readFile(filePath, "utf-8");
68854
- const relativePath = path29.relative(this.projectRoot, filePath).replace(/\\/g, "/");
70007
+ const content = await fs20.readFile(filePath, "utf-8");
70008
+ const relativePath = path30.relative(this.projectRoot, filePath).replace(/\\/g, "/");
68855
70009
  const parsed = entry.adapter.parse(relativePath, content);
68856
70010
  rules.push(...parsed);
68857
70011
  } catch {
@@ -68919,7 +70073,7 @@ var init_syncer = __esm({
68919
70073
  const entries = [];
68920
70074
  for (const adapter of this.adapters.values()) {
68921
70075
  const absolutePaths = adapter.filePatterns.map(
68922
- (p2) => path29.join(this.projectRoot, p2)
70076
+ (p2) => path30.join(this.projectRoot, p2)
68923
70077
  );
68924
70078
  entries.push({ adapter, paths: absolutePaths });
68925
70079
  }
@@ -68927,13 +70081,13 @@ var init_syncer = __esm({
68927
70081
  }
68928
70082
  /** Find files matching a glob-like path (simple implementation) */
68929
70083
  async findFiles(pattern) {
68930
- const dir = path29.dirname(pattern);
68931
- const fileGlob = path29.basename(pattern);
70084
+ const dir = path30.dirname(pattern);
70085
+ const fileGlob = path30.basename(pattern);
68932
70086
  try {
68933
- const stat = await fs19.stat(dir);
70087
+ const stat = await fs20.stat(dir);
68934
70088
  if (!stat.isDirectory()) {
68935
70089
  try {
68936
- await fs19.access(pattern);
70090
+ await fs20.access(pattern);
68937
70091
  return [pattern];
68938
70092
  } catch {
68939
70093
  return [];
@@ -68941,7 +70095,7 @@ var init_syncer = __esm({
68941
70095
  }
68942
70096
  } catch {
68943
70097
  try {
68944
- await fs19.access(pattern);
70098
+ await fs20.access(pattern);
68945
70099
  return [pattern];
68946
70100
  } catch {
68947
70101
  return [];
@@ -68949,16 +70103,16 @@ var init_syncer = __esm({
68949
70103
  }
68950
70104
  if (fileGlob.includes("*")) {
68951
70105
  try {
68952
- const files = await fs19.readdir(dir);
70106
+ const files = await fs20.readdir(dir);
68953
70107
  const ext = fileGlob.replace("*", "");
68954
- return files.filter((f4) => ext ? f4.endsWith(ext) : true).map((f4) => path29.join(dir, f4));
70108
+ return files.filter((f4) => ext ? f4.endsWith(ext) : true).map((f4) => path30.join(dir, f4));
68955
70109
  } catch {
68956
70110
  return [];
68957
70111
  }
68958
70112
  }
68959
70113
  try {
68960
- await fs19.access(path29.join(dir, fileGlob));
68961
- return [path29.join(dir, fileGlob)];
70114
+ await fs20.access(path30.join(dir, fileGlob));
70115
+ return [path30.join(dir, fileGlob)];
68962
70116
  } catch {
68963
70117
  return [];
68964
70118
  }
@@ -69193,10 +70347,10 @@ var init_engine3 = __esm({
69193
70347
  pathsToCheck.push(join25(homedir29(), ".gemini", "antigravity", "mcp_config.json"));
69194
70348
  }
69195
70349
  const merged = /* @__PURE__ */ new Map();
69196
- for (const path37 of pathsToCheck) {
69197
- if (existsSync20(path37)) {
70350
+ for (const path38 of pathsToCheck) {
70351
+ if (existsSync20(path38)) {
69198
70352
  try {
69199
- const content = readFileSync13(path37, "utf-8");
70353
+ const content = readFileSync13(path38, "utf-8");
69200
70354
  const servers = adapter.parse(content);
69201
70355
  for (const s2 of servers) {
69202
70356
  if (!merged.has(s2.name)) merged.set(s2.name, s2);
@@ -70173,8 +71327,8 @@ __export(server_exports, {
70173
71327
  startDashboard: () => startDashboard
70174
71328
  });
70175
71329
  import { createServer } from "http";
70176
- import { promises as fs20 } from "fs";
70177
- import path30 from "path";
71330
+ import { promises as fs21 } from "fs";
71331
+ import path31 from "path";
70178
71332
  import { exec } from "child_process";
70179
71333
  function sendJson(res, data, status = 200) {
70180
71334
  res.writeHead(status, {
@@ -70652,7 +71806,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
70652
71806
  const aliasModule = await Promise.resolve().then(() => (init_aliases(), aliases_exports));
70653
71807
  canonicalId = await aliasModule.getCanonicalId(effectiveProjectId);
70654
71808
  const { promises: fsP } = await import("fs");
70655
- const registryPath = path30.join(baseDir, ".project-aliases.json");
71809
+ const registryPath = path31.join(baseDir, ".project-aliases.json");
70656
71810
  const raw = await fsP.readFile(registryPath, "utf-8");
70657
71811
  const registry2 = JSON.parse(raw);
70658
71812
  aliasGroups = registry2.groups || [];
@@ -70767,14 +71921,14 @@ async function serveStatic(req, res, staticDir) {
70767
71921
  if (urlPath === "/" || !urlPath.includes(".")) {
70768
71922
  urlPath = "/index.html";
70769
71923
  }
70770
- const filePath = path30.join(staticDir, urlPath);
71924
+ const filePath = path31.join(staticDir, urlPath);
70771
71925
  if (!filePath.startsWith(staticDir)) {
70772
71926
  sendError(res, "Forbidden", 403);
70773
71927
  return;
70774
71928
  }
70775
71929
  try {
70776
- const data = await fs20.readFile(filePath);
70777
- const ext = path30.extname(filePath);
71930
+ const data = await fs21.readFile(filePath);
71931
+ const ext = path31.extname(filePath);
70778
71932
  res.writeHead(200, {
70779
71933
  "Content-Type": MIME_TYPES[ext] || "application/octet-stream",
70780
71934
  "Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
@@ -70784,7 +71938,7 @@ async function serveStatic(req, res, staticDir) {
70784
71938
  res.end(data);
70785
71939
  } catch {
70786
71940
  try {
70787
- const indexData = await fs20.readFile(path30.join(staticDir, "index.html"));
71941
+ const indexData = await fs21.readFile(path31.join(staticDir, "index.html"));
70788
71942
  res.writeHead(200, {
70789
71943
  "Content-Type": "text/html; charset=utf-8",
70790
71944
  "Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
@@ -71225,9 +72379,9 @@ __export(hooks_path_exports, {
71225
72379
  resolveHooksDir: () => resolveHooksDir
71226
72380
  });
71227
72381
  import { existsSync as existsSync22, readFileSync as readFileSync15, statSync as statSync5, mkdirSync as mkdirSync6 } from "fs";
71228
- import path31 from "path";
72382
+ import path32 from "path";
71229
72383
  function resolveGitDir(projectRoot) {
71230
- const dotGit = path31.join(projectRoot, ".git");
72384
+ const dotGit = path32.join(projectRoot, ".git");
71231
72385
  if (!existsSync22(dotGit)) return null;
71232
72386
  const stat = statSync5(dotGit);
71233
72387
  if (stat.isDirectory()) {
@@ -71239,7 +72393,7 @@ function resolveGitDir(projectRoot) {
71239
72393
  const match = content.match(/^gitdir:\s*(.+)$/);
71240
72394
  if (match) {
71241
72395
  const gitdir = match[1].trim();
71242
- const resolved = path31.isAbsolute(gitdir) ? gitdir : path31.resolve(projectRoot, gitdir);
72396
+ const resolved = path32.isAbsolute(gitdir) ? gitdir : path32.resolve(projectRoot, gitdir);
71243
72397
  if (existsSync22(resolved)) {
71244
72398
  return resolved;
71245
72399
  }
@@ -71252,10 +72406,10 @@ function resolveGitDir(projectRoot) {
71252
72406
  function resolveHooksDir(projectRoot) {
71253
72407
  const gitDir = resolveGitDir(projectRoot);
71254
72408
  if (!gitDir) return null;
71255
- const hooksDir = path31.join(gitDir, "hooks");
72409
+ const hooksDir = path32.join(gitDir, "hooks");
71256
72410
  return {
71257
72411
  hooksDir,
71258
- hookPath: path31.join(hooksDir, "post-commit")
72412
+ hookPath: path32.join(hooksDir, "post-commit")
71259
72413
  };
71260
72414
  }
71261
72415
  function ensureHooksDir(projectRoot) {
@@ -71633,7 +72787,7 @@ The path should point to a directory containing a .git folder.`
71633
72787
  };
71634
72788
  const server = existingServer ?? new McpServer({
71635
72789
  name: "memorix",
71636
- version: true ? "1.2.10" : "1.0.1"
72790
+ version: true ? "1.3.0" : "1.0.1"
71637
72791
  });
71638
72792
  const originalRegisterTool = server.registerTool.bind(server);
71639
72793
  server.registerTool = ((name, ...args) => {
@@ -71713,7 +72867,7 @@ The path should point to a directory containing a .git folder.`
71713
72867
  "memorix_store",
71714
72868
  {
71715
72869
  title: "Store Memory",
71716
- description: "Store a new observation/memory. Automatically indexed for search. Use type to classify: gotcha ([GOTCHA] critical pitfall), decision ([DECISION] architecture choice), problem-solution ([FIX] bug fix), how-it-works ([INFO] explanation), what-changed ([CHANGE] change), discovery ([DISCOVERY] insight), why-it-exists ([WHY] rationale), trade-off ([TRADEOFF] compromise), session-request ([SESSION] original goal). Project visibility is the default. Personal or team visibility requires an explicitly joined coordination identity. For a read-only task, do not store unless the user explicitly asks to save a record.",
72870
+ description: "Store a new observation/memory. Automatically indexed for search. Use type to classify: gotcha ([GOTCHA] critical pitfall), decision ([DECISION] architecture choice), problem-solution ([FIX] bug fix), how-it-works ([INFO] explanation), what-changed ([CHANGE] change), discovery ([DISCOVERY] insight), why-it-exists ([WHY] rationale), trade-off ([TRADEOFF] compromise), session-request ([SESSION] original goal). Project visibility is the default. Personal or team visibility requires an explicitly joined coordination identity. Set longTerm only when the caller explicitly wants an additional source-backed long-term candidate; it is never injected until an operator records a review through the CLI. For a read-only task, do not store unless the user explicitly asks to save a record.",
71717
72871
  inputSchema: {
71718
72872
  entityName: external_exports.string().describe('The entity this observation belongs to (e.g., "auth-module", "port-config")'),
71719
72873
  type: external_exports.enum(OBSERVATION_TYPES2).describe("Observation type for classification"),
@@ -71735,30 +72889,43 @@ The path should point to a directory containing a .git folder.`
71735
72889
  visibility: external_exports.enum(["personal", "project", "team"]).optional().describe(
71736
72890
  "Retrieval scope. Project is the normal shared default; personal/team require memorix_session_start with joinTeam=true."
71737
72891
  ),
72892
+ longTerm: external_exports.object({
72893
+ kind: external_exports.enum(["episodic", "semantic", "procedural"]).describe("Cognitive kind for an additional long-term candidate."),
72894
+ scope: external_exports.enum(["project", "user", "team"]).optional().default("project").describe("Long-term scope. User capture is private source evidence and needs a bound agent identity."),
72895
+ tags: external_exports.array(external_exports.string()).optional().describe("Small set of retrieval tags for the candidate."),
72896
+ applicability: external_exports.string().optional().describe("When this durable fact or procedure applies.")
72897
+ }).optional().describe("Optional explicit request to create a source-backed long-term candidate alongside this observation. Candidates are not automatically injected."),
71738
72898
  overrideReadOnly: external_exports.boolean().optional().describe(
71739
72899
  "Use only when the user explicitly asks to save memory during a read-only or no-modification task."
71740
72900
  )
71741
72901
  }
71742
72902
  },
71743
- async ({ entityName: rawEntityName, type: rawType, title: rawTitle, narrative, facts, filesModified, concepts, topicKey, progress, relatedCommits, relatedEntities, visibility, overrideReadOnly }) => {
72903
+ async ({ entityName: rawEntityName, type: rawType, title: rawTitle, narrative, facts, filesModified, concepts, topicKey, progress, relatedCommits, relatedEntities, visibility, longTerm, overrideReadOnly }) => {
71744
72904
  const unresolved = requireResolvedProject("store memory in the current project");
71745
72905
  if (unresolved) return unresolved;
71746
72906
  const readOnlyBoundary = blockReadOnlyAutopilotWrite(overrideReadOnly);
71747
72907
  if (readOnlyBoundary) return readOnlyBoundary;
71748
- const requestedVisibility = visibility ?? "project";
72908
+ const requestedVisibility = longTerm?.scope === "user" ? "personal" : longTerm?.scope === "team" ? "team" : visibility;
72909
+ const effectiveVisibility = requestedVisibility ?? "project";
71749
72910
  const reader = getObservationReader();
71750
- if (requestedVisibility !== "project" && !currentAgentId) {
72911
+ if (effectiveVisibility !== "project" && !currentAgentId) {
71751
72912
  return {
71752
72913
  content: [{ type: "text", text: "Personal or team memory requires memorix_session_start with joinTeam=true so Memorix can bind an owner." }],
71753
72914
  isError: true
71754
72915
  };
71755
72916
  }
71756
- if (requestedVisibility === "team" && !reader.isTeamMember) {
72917
+ if (effectiveVisibility === "team" && !reader.isTeamMember) {
71757
72918
  return {
71758
72919
  content: [{ type: "text", text: "Team memory requires an active coordination membership in the current project." }],
71759
72920
  isError: true
71760
72921
  };
71761
72922
  }
72923
+ if (longTerm?.scope === "team" && !reader.isTeamMember) {
72924
+ return {
72925
+ content: [{ type: "text", text: "Team long-term memory requires an active coordination membership in the current project." }],
72926
+ isError: true
72927
+ };
72928
+ }
71762
72929
  try {
71763
72930
  return await withFreshIndex(async () => {
71764
72931
  let entityName = rawEntityName;
@@ -71780,7 +72947,7 @@ The path should point to a directory containing a .git folder.`
71780
72947
  const useFormation = formationMode === "active";
71781
72948
  let formationResult = null;
71782
72949
  let formationNote = "";
71783
- if (useFormation && !topicKey && !progress) {
72950
+ if (useFormation && !topicKey && !progress && !longTerm) {
71784
72951
  let currentFormationStage = "setup";
71785
72952
  const completedFormationStages = {};
71786
72953
  const formationStartTime = Date.now();
@@ -71931,7 +73098,7 @@ ${modeIcon} Formation[active]: ${formationResult.evaluation.category} (${formati
71931
73098
  }
71932
73099
  let compactAction = "";
71933
73100
  let compactMerged = false;
71934
- if (!useFormation && !topicKey && !progress) {
73101
+ if (!useFormation && !topicKey && !progress && !longTerm) {
71935
73102
  try {
71936
73103
  const searchResult = await compactSearch({
71937
73104
  query: `${title} ${narrative.substring(0, 200)}`,
@@ -72088,9 +73255,33 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
72088
73255
  sourceDetail: "explicit",
72089
73256
  valueCategory: formationResult?.evaluation.category,
72090
73257
  createdByAgentId: currentAgentId,
72091
- visibility,
73258
+ visibility: requestedVisibility,
72092
73259
  visibilityReader: reader
72093
73260
  });
73261
+ let longTermNote = "";
73262
+ if (longTerm) {
73263
+ try {
73264
+ const { promoteObservationToLongTermMemory: promoteObservationToLongTermMemory2 } = await Promise.resolve().then(() => (init_long_term(), long_term_exports));
73265
+ const promoted = await promoteObservationToLongTermMemory2({
73266
+ dataDir: projectDir2,
73267
+ observation: obs,
73268
+ scope: longTerm.scope,
73269
+ kind: longTerm.kind,
73270
+ tags: longTerm.tags,
73271
+ applicability: longTerm.applicability,
73272
+ reader: {
73273
+ projectId: project.id,
73274
+ ...reader.agentId ? { agentId: reader.agentId } : {},
73275
+ ...reader.isTeamMember ? { isTeamMember: true } : {}
73276
+ }
73277
+ });
73278
+ longTermNote = `
73279
+ Long-term candidate: ${promoted.memory.id} (${promoted.memory.kind}/${promoted.memory.scope}). Review it with the CLI before it is delivered automatically.`;
73280
+ } catch (longTermError) {
73281
+ longTermNote = `
73282
+ [WARN] Observation stored, but long-term candidate was not created: ${longTermError instanceof Error ? longTermError.message : "unknown error"}`;
73283
+ }
73284
+ }
72094
73285
  await graphManager.addObservations([
72095
73286
  { entityName, contents: [`[#${obs.id}] ${title}`] }
72096
73287
  ]);
@@ -72107,7 +73298,7 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
72107
73298
  const enrichment = enrichmentParts.length > 0 ? `
72108
73299
  Auto-enriched: ${enrichmentParts.join(", ")}` : "";
72109
73300
  const action = upserted ? "[UPDATED] Updated" : "[OK] Stored";
72110
- if (!useFormation && !topicKey && !progress) {
73301
+ if (!useFormation && !topicKey && !progress && !longTerm) {
72111
73302
  const shadowFormation = async () => {
72112
73303
  let oldCompactDecision = null;
72113
73304
  try {
@@ -72197,7 +73388,7 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
72197
73388
  {
72198
73389
  type: "text",
72199
73390
  text: `${action} observation #${obs.id} "${title}" (~${obs.tokens} tokens)
72200
- Entity: ${entityName} | Type: ${type} | Project: ${project.id}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ""}${compactAction}${compressionNote}${enrichment}${formationNote}${attributionWarning}`
73391
+ Entity: ${entityName} | Type: ${type} | Project: ${project.id}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ""}${compactAction}${compressionNote}${enrichment}${formationNote}${attributionWarning}${longTermNote}`
72201
73392
  }
72202
73393
  ]
72203
73394
  };
@@ -72570,7 +73761,8 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
72570
73761
  } : {},
72571
73762
  ...external.outline ? { semanticCode: external.outline } : {},
72572
73763
  providerQuality: external.quality,
72573
- ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {}
73764
+ ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
73765
+ reader: getObservationReader()
72574
73766
  });
72575
73767
  const text = buildContextPackPrompt2(pack);
72576
73768
  return {
@@ -73244,7 +74436,7 @@ ${actions.join("\n")}`
73244
74436
  "memorix_detail",
73245
74437
  {
73246
74438
  title: "Memory Details",
73247
- description: 'Fetch full observation or mini-skill details \u2014 includes source kind (explicit memory / hook trace / git evidence), value category, and cross-references (~500-1000 tokens each). Do not re-fetch content already covered by a complete memorix_project_context brief unless a specific fact is still missing or the user asks for deeper history; provide purpose when intentionally expanding. Always use memorix_search first to find relevant IDs, then fetch only what you need. Accepts typed refs from search results (e.g. "obs:42", "skill:3") via the typedRefs field, or legacy numeric ids / object refs for backward compatibility.',
74439
+ description: 'Fetch full observation, mini-skill, or curated durable-memory details \u2014 includes source kind (explicit memory / hook trace / git evidence), value category, and cross-references (~500-1000 tokens each). Do not re-fetch content already covered by a complete memorix_project_context brief unless a specific fact is still missing or the user asks for deeper history; provide purpose when intentionally expanding. Always use memorix_search first to find relevant IDs, then fetch only what you need. Accepts typed refs from search results (e.g. "obs:42", "skill:3") and durable refs from a project brief (e.g. "durable:<uuid>") via the typedRefs field, or legacy numeric ids / object refs for backward compatibility.',
73248
74440
  inputSchema: {
73249
74441
  ids: external_exports.array(external_exports.number()).optional().describe("Observation IDs to fetch (legacy, from memorix_search results)"),
73250
74442
  refs: external_exports.array(
@@ -73253,7 +74445,7 @@ ${actions.join("\n")}`
73253
74445
  projectId: external_exports.string().optional().describe("Project ID for global-search disambiguation")
73254
74446
  })
73255
74447
  ).optional().describe("Explicit observation refs. Prefer this for global search results."),
73256
- typedRefs: external_exports.array(external_exports.string()).optional().describe('Typed memory refs from search results, e.g. "obs:42", "skill:3", "obs:42@org/proj"'),
74448
+ typedRefs: external_exports.array(external_exports.string()).optional().describe('Typed memory refs from search results or a project brief, e.g. "obs:42", "skill:3", "durable:<uuid>", "obs:42@org/proj"'),
73257
74449
  purpose: external_exports.string().optional().describe(
73258
74450
  "Why this must expand beyond the latest Autopilot brief. Name the missing fact or the user's explicit request."
73259
74451
  ),
@@ -73266,14 +74458,19 @@ ${actions.join("\n")}`
73266
74458
  const safeIds = coerceNumberArray(ids);
73267
74459
  const safeRefs = coerceObservationRefs(refs);
73268
74460
  const safeTypedRefs = coerceStringArray(typedRefs);
73269
- const hasCrossProjectRef = safeRefs.some((ref) => ref.projectId && ref.projectId !== project.id) || safeTypedRefs.some((ref) => ref.includes("@") && !ref.endsWith(`@${project.id}`));
74461
+ const durableIds = safeTypedRefs.flatMap((ref) => {
74462
+ const match = /^durable:([0-9a-f-]{36})$/i.exec(ref.trim());
74463
+ return match ? [match[1]] : [];
74464
+ });
74465
+ const observationTypedRefs = safeTypedRefs.filter((ref) => !/^durable:/i.test(ref.trim()));
74466
+ const hasCrossProjectRef = safeRefs.some((ref) => ref.projectId && ref.projectId !== project.id) || observationTypedRefs.some((ref) => ref.includes("@") && !ref.endsWith(`@${project.id}`));
73270
74467
  if (!hasCrossProjectRef) {
73271
74468
  const boundary = requireExplicitAutopilotExpansion("memorix_detail", purpose);
73272
74469
  if (boundary) return boundary;
73273
74470
  const requestedObservationIds = [
73274
74471
  ...safeIds,
73275
74472
  ...safeRefs.map((ref) => ref.id),
73276
- ...safeTypedRefs.flatMap((ref) => {
74473
+ ...observationTypedRefs.flatMap((ref) => {
73277
74474
  const match = /^obs:(\d+)(?:@.+)?$/i.exec(ref.trim());
73278
74475
  return match ? [Number(match[1])] : [];
73279
74476
  })
@@ -73281,15 +74478,36 @@ ${actions.join("\n")}`
73281
74478
  const duplicate = blockCoveredAutopilotEvidence("memorix_detail", requestedObservationIds, force);
73282
74479
  if (duplicate) return duplicate;
73283
74480
  }
73284
- let result;
74481
+ const formatted = [];
73285
74482
  try {
73286
- const reader = getObservationReader(hasCrossProjectRef ? "global" : "project");
73287
- if (safeTypedRefs.length > 0) {
73288
- result = await compactDetail(safeTypedRefs, { reader });
73289
- } else if (safeRefs.length > 0) {
73290
- result = await compactDetail(safeRefs, { reader });
73291
- } else {
73292
- result = await compactDetail(safeIds.map((id) => ({ id, projectId: project.id })), { reader });
74483
+ if (durableIds.length > 0) {
74484
+ const [{ getLongTermMemoryDetail: getLongTermMemoryDetail2 }, { resolveLocalMemoryOwner: resolveLocalMemoryOwner2 }] = await Promise.all([
74485
+ Promise.resolve().then(() => (init_long_term(), long_term_exports)),
74486
+ Promise.resolve().then(() => (init_owner(), owner_exports))
74487
+ ]);
74488
+ const owner = await resolveLocalMemoryOwner2(projectDir2, { create: false });
74489
+ const observationReader = getObservationReader();
74490
+ const durableReader = {
74491
+ projectId: project.id,
74492
+ ...owner ? { ownerId: owner.id } : {},
74493
+ ...observationReader.agentId ? { agentId: observationReader.agentId } : {},
74494
+ ...observationReader.isTeamMember ? { isTeamMember: true } : {}
74495
+ };
74496
+ const details = await Promise.all(durableIds.slice(0, 5).map(async (id) => {
74497
+ try {
74498
+ return await getLongTermMemoryDetail2({ dataDir: projectDir2, id, reader: durableReader });
74499
+ } catch (error2) {
74500
+ return { error: error2 instanceof Error ? error2.message : String(error2), id };
74501
+ }
74502
+ }));
74503
+ formatted.push(JSON.stringify({ durableMemory: details }, null, 2));
74504
+ }
74505
+ if (observationTypedRefs.length > 0 || safeRefs.length > 0 || safeIds.length > 0) {
74506
+ const reader = getObservationReader(hasCrossProjectRef ? "global" : "project");
74507
+ const result = observationTypedRefs.length > 0 ? await compactDetail(observationTypedRefs, { reader }) : safeRefs.length > 0 ? await compactDetail(safeRefs, { reader }) : await compactDetail(safeIds.map((id) => ({ id, projectId: project.id })), { reader });
74508
+ formatted.push(
74509
+ result.documents.length > 0 ? result.formatted : observationTypedRefs.length > 0 ? `No memories found for refs: ${observationTypedRefs.join(", ")}` : safeRefs.length > 0 ? `No memories found for refs: ${safeRefs.map((ref) => `${ref.projectId ?? "current"}#${ref.id}`).join(", ")}` : `No memories found for IDs: ${safeIds.join(", ")}`
74510
+ );
73293
74511
  }
73294
74512
  } catch (err) {
73295
74513
  return { content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }], isError: true };
@@ -73298,7 +74516,7 @@ ${actions.join("\n")}`
73298
74516
  content: [
73299
74517
  {
73300
74518
  type: "text",
73301
- text: result.documents.length > 0 ? result.formatted : safeTypedRefs.length > 0 ? `No memories found for refs: ${safeTypedRefs.join(", ")}` : safeRefs.length > 0 ? `No memories found for refs: ${safeRefs.map((ref) => `${ref.projectId ?? "current"}#${ref.id}`).join(", ")}` : `No memories found for IDs: ${safeIds.join(", ")}`
74519
+ text: formatted.length > 0 ? formatted.join("\n\n") : safeTypedRefs.length > 0 ? `No memories found for refs: ${safeTypedRefs.join(", ")}` : safeRefs.length > 0 ? `No memories found for refs: ${safeRefs.map((ref) => `${ref.projectId ?? "current"}#${ref.id}`).join(", ")}` : `No memories found for IDs: ${safeIds.join(", ")}`
73302
74520
  }
73303
74521
  ]
73304
74522
  };
@@ -74018,9 +75236,9 @@ ${skill2.content}` }]
74018
75236
  lines.push(`- **Description**: ${sk.description}`);
74019
75237
  lines.push(`- **Observations**: ${sk.content.split("\n").length} lines of knowledge`);
74020
75238
  if (write && target) {
74021
- const path37 = engine.writeSkill(sk, target);
74022
- if (path37) {
74023
- lines.push(`- [OK] **Written**: \`${path37}\``);
75239
+ const path38 = engine.writeSkill(sk, target);
75240
+ if (path38) {
75241
+ lines.push(`- [OK] **Written**: \`${path38}\``);
74024
75242
  } else {
74025
75243
  lines.push(`- [ERROR] Failed to write`);
74026
75244
  }
@@ -75852,8 +77070,8 @@ var init_serve = __esm({
75852
77070
  safeCwd = homedir34();
75853
77071
  }
75854
77072
  const { existsSync: existsSync31, readFileSync: readFileSync23 } = await import("fs");
75855
- const path37 = await import("path");
75856
- const lastRootFile = path37.join(homedir34(), ".memorix", "last-project-root");
77073
+ const path38 = await import("path");
77074
+ const lastRootFile = path38.join(homedir34(), ".memorix", "last-project-root");
75857
77075
  let lastKnownProjectRoot;
75858
77076
  if (existsSync31(lastRootFile)) {
75859
77077
  try {
@@ -75888,9 +77106,9 @@ var init_serve = __esm({
75888
77106
  if (detected) {
75889
77107
  try {
75890
77108
  const { writeFileSync: writeFileSync11, mkdirSync: mkdirSync11 } = await import("fs");
75891
- const memorixDir = path37.join(homedir34(), ".memorix");
77109
+ const memorixDir = path38.join(homedir34(), ".memorix");
75892
77110
  mkdirSync11(memorixDir, { recursive: true });
75893
- writeFileSync11(path37.join(memorixDir, "last-project-root"), detected.rootPath, "utf-8");
77111
+ writeFileSync11(path38.join(memorixDir, "last-project-root"), detected.rootPath, "utf-8");
75894
77112
  } catch {
75895
77113
  }
75896
77114
  }
@@ -77431,7 +78649,7 @@ var init_serve_http = __esm({
77431
78649
  },
77432
78650
  run: async ({ args }) => {
77433
78651
  const { createServer: createServer2 } = await import("http");
77434
- const { randomUUID: randomUUID11 } = await import("crypto");
78652
+ const { randomUUID: randomUUID14 } = await import("crypto");
77435
78653
  const { StreamableHTTPServerTransport: StreamableHTTPServerTransport2 } = await Promise.resolve().then(() => (init_streamableHttp(), streamableHttp_exports));
77436
78654
  const { isInitializeRequest: isInitializeRequest2 } = await Promise.resolve().then(() => (init_types4(), types_exports));
77437
78655
  const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server4(), server_exports2));
@@ -77615,7 +78833,7 @@ var init_serve_http = __esm({
77615
78833
  if (!sessionId && isInitializeRequest2(body)) {
77616
78834
  let createdState = null;
77617
78835
  const transport = new StreamableHTTPServerTransport2({
77618
- sessionIdGenerator: () => randomUUID11(),
78836
+ sessionIdGenerator: () => randomUUID14(),
77619
78837
  enableJsonResponse: true,
77620
78838
  onsessioninitialized: (sid) => {
77621
78839
  if (createdState) sessions.set(sid, createdState);
@@ -78982,8 +80200,8 @@ var init_sync = __esm({
78982
80200
  }
78983
80201
  const { detectProject: detectProject2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
78984
80202
  const { RulesSyncer: RulesSyncer2 } = await Promise.resolve().then(() => (init_syncer(), syncer_exports));
78985
- const { promises: fs27 } = await import("fs");
78986
- const path37 = await import("path");
80203
+ const { promises: fs28 } = await import("fs");
80204
+ const path38 = await import("path");
78987
80205
  we("memorix sync");
78988
80206
  const project = detectProject2();
78989
80207
  if (!project) {
@@ -79055,9 +80273,9 @@ var init_sync = __esm({
79055
80273
  process.exit(0);
79056
80274
  }
79057
80275
  for (const file of files) {
79058
- const fullPath = path37.join(project.rootPath, file.filePath);
79059
- await fs27.mkdir(path37.dirname(fullPath), { recursive: true });
79060
- await fs27.writeFile(fullPath, file.content, "utf-8");
80276
+ const fullPath = path38.join(project.rootPath, file.filePath);
80277
+ await fs28.mkdir(path38.dirname(fullPath), { recursive: true });
80278
+ await fs28.writeFile(fullPath, file.content, "utf-8");
79061
80279
  v3.success(`Written: ${file.filePath}`);
79062
80280
  }
79063
80281
  fe2(`Synced ${files.length} rule(s) to ${target} format`);
@@ -80944,8 +82162,8 @@ var hooks_preview_exports = {};
80944
82162
  __export(hooks_preview_exports, {
80945
82163
  default: () => hooks_preview_default
80946
82164
  });
80947
- import * as fs21 from "fs/promises";
80948
- import * as path32 from "path";
82165
+ import * as fs22 from "fs/promises";
82166
+ import * as path33 from "path";
80949
82167
  function estimateFileSize(agent, configPath) {
80950
82168
  const sizes = {
80951
82169
  claude: "~2KB",
@@ -80965,30 +82183,30 @@ function getRulesPath(agent, cwd, global2) {
80965
82183
  if (global2) {
80966
82184
  switch (agent) {
80967
82185
  case "cursor":
80968
- return path32.join(home, ".cursor", "rules", "memorix.mdc");
82186
+ return path33.join(home, ".cursor", "rules", "memorix.mdc");
80969
82187
  case "codex":
80970
- return path32.join(home, ".codex", "AGENTS.md");
82188
+ return path33.join(home, ".codex", "AGENTS.md");
80971
82189
  case "opencode":
80972
- return path32.join(home, ".config", "opencode", "AGENTS.md");
82190
+ return path33.join(home, ".config", "opencode", "AGENTS.md");
80973
82191
  case "antigravity":
80974
- return path32.join(home, ".gemini", "GEMINI.md");
82192
+ return path33.join(home, ".gemini", "GEMINI.md");
80975
82193
  case "trae":
80976
- return path32.join(home, ".trae", "rules", "project_rules.md");
82194
+ return path33.join(home, ".trae", "rules", "project_rules.md");
80977
82195
  default:
80978
82196
  return "";
80979
82197
  }
80980
82198
  } else {
80981
82199
  switch (agent) {
80982
82200
  case "cursor":
80983
- return path32.join(cwd, ".cursor", "rules", "memorix.mdc");
82201
+ return path33.join(cwd, ".cursor", "rules", "memorix.mdc");
80984
82202
  case "codex":
80985
- return path32.join(cwd, "AGENTS.md");
82203
+ return path33.join(cwd, "AGENTS.md");
80986
82204
  case "opencode":
80987
- return path32.join(cwd, "AGENTS.md");
82205
+ return path33.join(cwd, "AGENTS.md");
80988
82206
  case "antigravity":
80989
- return path32.join(cwd, "GEMINI.md");
82207
+ return path33.join(cwd, "GEMINI.md");
80990
82208
  case "trae":
80991
- return path32.join(cwd, ".trae", "rules", "project_rules.md");
82209
+ return path33.join(cwd, ".trae", "rules", "project_rules.md");
80992
82210
  default:
80993
82211
  return "";
80994
82212
  }
@@ -81045,7 +82263,7 @@ var init_hooks_preview = __esm({
81045
82263
  const configPath = global2 ? getGlobalConfigPath2(agent) : getProjectConfigPath2(agent, cwd);
81046
82264
  let action;
81047
82265
  try {
81048
- await fs21.access(configPath);
82266
+ await fs22.access(configPath);
81049
82267
  action = "modify";
81050
82268
  } catch {
81051
82269
  action = "create";
@@ -81060,7 +82278,7 @@ var init_hooks_preview = __esm({
81060
82278
  if (["cursor", "codex", "opencode", "antigravity", "trae"].includes(agent)) {
81061
82279
  const rulesPath = getRulesPath(agent, cwd, global2);
81062
82280
  try {
81063
- await fs21.access(rulesPath);
82281
+ await fs22.access(rulesPath);
81064
82282
  previewItems.push({
81065
82283
  agent,
81066
82284
  path: rulesPath,
@@ -81077,10 +82295,10 @@ var init_hooks_preview = __esm({
81077
82295
  }
81078
82296
  }
81079
82297
  if (agent === "kiro") {
81080
- const hooksDir = path32.dirname(configPath);
82298
+ const hooksDir = path33.dirname(configPath);
81081
82299
  previewItems.push({
81082
82300
  agent,
81083
- path: path32.join(hooksDir, "*.kiro.hook"),
82301
+ path: path33.join(hooksDir, "*.kiro.hook"),
81084
82302
  action: "create",
81085
82303
  size: "~500B each"
81086
82304
  });
@@ -81851,9 +83069,9 @@ __export(ingest_image_exports, {
81851
83069
  default: () => ingest_image_default
81852
83070
  });
81853
83071
  import { readFileSync as readFileSync16 } from "fs";
81854
- import path33 from "path";
83072
+ import path34 from "path";
81855
83073
  function inferMimeType(filePath) {
81856
- const ext = path33.extname(filePath).toLowerCase();
83074
+ const ext = path34.extname(filePath).toLowerCase();
81857
83075
  switch (ext) {
81858
83076
  case ".jpg":
81859
83077
  case ".jpeg":
@@ -81896,9 +83114,9 @@ var init_ingest_image = __esm({
81896
83114
  return;
81897
83115
  }
81898
83116
  const { project, reader, identity } = await getCliProjectContext();
81899
- const resolvedPath = path33.resolve(project.rootPath, imagePath);
83117
+ const resolvedPath = path34.resolve(project.rootPath, imagePath);
81900
83118
  const base642 = readFileSync16(resolvedPath).toString("base64");
81901
- const filename = path33.basename(resolvedPath);
83119
+ const filename = path34.basename(resolvedPath);
81902
83120
  const analysis = await analyzeImage({
81903
83121
  base64: base642,
81904
83122
  filename,
@@ -82162,7 +83380,7 @@ __export(background_exports, {
82162
83380
  doStart: () => doStart,
82163
83381
  doStop: () => doStop
82164
83382
  });
82165
- import * as fs22 from "fs";
83383
+ import * as fs23 from "fs";
82166
83384
  import { spawn as spawn4, execSync as execSync5 } from "child_process";
82167
83385
  import { randomBytes } from "crypto";
82168
83386
  function getMemorixDir() {
@@ -82180,7 +83398,7 @@ function getLogFilePath() {
82180
83398
  }
82181
83399
  function loadState() {
82182
83400
  try {
82183
- const data = fs22.readFileSync(getStateFilePath(), "utf-8");
83401
+ const data = fs23.readFileSync(getStateFilePath(), "utf-8");
82184
83402
  return JSON.parse(data);
82185
83403
  } catch {
82186
83404
  return null;
@@ -82188,12 +83406,12 @@ function loadState() {
82188
83406
  }
82189
83407
  function saveState(state) {
82190
83408
  const dir = getMemorixDir();
82191
- if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
82192
- fs22.writeFileSync(getStateFilePath(), JSON.stringify(state, null, 2));
83409
+ if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
83410
+ fs23.writeFileSync(getStateFilePath(), JSON.stringify(state, null, 2));
82193
83411
  }
82194
83412
  function clearState() {
82195
83413
  try {
82196
- fs22.unlinkSync(getStateFilePath());
83414
+ fs23.unlinkSync(getStateFilePath());
82197
83415
  } catch {
82198
83416
  }
82199
83417
  }
@@ -82260,7 +83478,7 @@ async function doStart(port) {
82260
83478
  } else {
82261
83479
  try {
82262
83480
  const heartbeatPath = getMemorixDir() + "/background.heartbeat";
82263
- const hbData = fs22.readFileSync(heartbeatPath, "utf-8");
83481
+ const hbData = fs23.readFileSync(heartbeatPath, "utf-8");
82264
83482
  const hb = JSON.parse(hbData);
82265
83483
  const age = Date.now() - hb.heartbeatAt;
82266
83484
  if (age < 12e4) {
@@ -82268,7 +83486,7 @@ async function doStart(port) {
82268
83486
  console.log(" The control plane likely crashed. Auto-restarting...");
82269
83487
  }
82270
83488
  try {
82271
- fs22.unlinkSync(heartbeatPath);
83489
+ fs23.unlinkSync(heartbeatPath);
82272
83490
  } catch {
82273
83491
  }
82274
83492
  } catch {
@@ -82289,19 +83507,19 @@ async function doStart(port) {
82289
83507
  }
82290
83508
  try {
82291
83509
  const readyFile = getMemorixDir() + "/background.ready";
82292
- if (fs22.existsSync(readyFile)) fs22.unlinkSync(readyFile);
83510
+ if (fs23.existsSync(readyFile)) fs23.unlinkSync(readyFile);
82293
83511
  } catch {
82294
83512
  }
82295
83513
  const logFile = getLogFilePath();
82296
83514
  const dir = getMemorixDir();
82297
- if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
82298
- if (fs22.existsSync(logFile)) {
83515
+ if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
83516
+ if (fs23.existsSync(logFile)) {
82299
83517
  try {
82300
- fs22.renameSync(logFile, logFile + ".prev");
83518
+ fs23.renameSync(logFile, logFile + ".prev");
82301
83519
  } catch {
82302
83520
  }
82303
83521
  }
82304
- const logFd = fs22.openSync(logFile, "a");
83522
+ const logFd = fs23.openSync(logFile, "a");
82305
83523
  const cliEntry = process.argv[1];
82306
83524
  const child = spawn4(process.execPath, [cliEntry, "serve-http", "--port", String(port)], {
82307
83525
  detached: true,
@@ -82311,7 +83529,7 @@ async function doStart(port) {
82311
83529
  windowsHide: true
82312
83530
  });
82313
83531
  child.unref();
82314
- fs22.closeSync(logFd);
83532
+ fs23.closeSync(logFd);
82315
83533
  const pid = child.pid;
82316
83534
  if (!pid) {
82317
83535
  console.error("[ERROR] Failed to spawn background process");
@@ -82381,7 +83599,7 @@ async function doStop() {
82381
83599
  console.log(`Background process (PID ${state.pid}) is not running. Cleaning up state.`);
82382
83600
  clearState();
82383
83601
  try {
82384
- fs22.unlinkSync(getMemorixDir() + "/background.ready");
83602
+ fs23.unlinkSync(getMemorixDir() + "/background.ready");
82385
83603
  } catch {
82386
83604
  }
82387
83605
  return;
@@ -82400,7 +83618,7 @@ async function doStop() {
82400
83618
  }
82401
83619
  clearState();
82402
83620
  try {
82403
- fs22.unlinkSync(getMemorixDir() + "/background.ready");
83621
+ fs23.unlinkSync(getMemorixDir() + "/background.ready");
82404
83622
  } catch {
82405
83623
  }
82406
83624
  return;
@@ -82437,7 +83655,7 @@ async function doStop() {
82437
83655
  }
82438
83656
  clearState();
82439
83657
  try {
82440
- fs22.unlinkSync(getMemorixDir() + "/background.ready");
83658
+ fs23.unlinkSync(getMemorixDir() + "/background.ready");
82441
83659
  } catch {
82442
83660
  }
82443
83661
  console.log("[OK] Control plane stopped.");
@@ -82513,7 +83731,7 @@ async function doStatus() {
82513
83731
  console.log(" Process has exited. Cleaning up stale state...");
82514
83732
  try {
82515
83733
  const heartbeatPath = getMemorixDir() + "/background.heartbeat";
82516
- const hbData = fs22.readFileSync(heartbeatPath, "utf-8");
83734
+ const hbData = fs23.readFileSync(heartbeatPath, "utf-8");
82517
83735
  const hb = JSON.parse(hbData);
82518
83736
  const age = Date.now() - hb.heartbeatAt;
82519
83737
  if (age < 3e5) {
@@ -82554,26 +83772,26 @@ async function doEnsure(port) {
82554
83772
  }
82555
83773
  function doLogs(follow, lines) {
82556
83774
  const logFile = getLogFilePath();
82557
- if (!fs22.existsSync(logFile)) {
83775
+ if (!fs23.existsSync(logFile)) {
82558
83776
  console.log("No log file found. Start the background service first:");
82559
83777
  console.log(" memorix background start");
82560
83778
  return;
82561
83779
  }
82562
83780
  if (follow) {
82563
- const content = fs22.readFileSync(logFile, "utf-8");
83781
+ const content = fs23.readFileSync(logFile, "utf-8");
82564
83782
  const existingLines = content.split("\n");
82565
83783
  const tail = existingLines.slice(-lines);
82566
83784
  console.log(tail.join("\n"));
82567
83785
  console.log("--- Following log (Ctrl+C to stop) ---");
82568
- let position = fs22.statSync(logFile).size;
82569
- const watcher = fs22.watch(logFile, () => {
83786
+ let position = fs23.statSync(logFile).size;
83787
+ const watcher = fs23.watch(logFile, () => {
82570
83788
  try {
82571
- const stat = fs22.statSync(logFile);
83789
+ const stat = fs23.statSync(logFile);
82572
83790
  if (stat.size > position) {
82573
- const fd = fs22.openSync(logFile, "r");
83791
+ const fd = fs23.openSync(logFile, "r");
82574
83792
  const buf = Buffer.alloc(stat.size - position);
82575
- fs22.readSync(fd, buf, 0, buf.length, position);
82576
- fs22.closeSync(fd);
83793
+ fs23.readSync(fd, buf, 0, buf.length, position);
83794
+ fs23.closeSync(fd);
82577
83795
  process.stdout.write(buf.toString("utf-8"));
82578
83796
  position = stat.size;
82579
83797
  }
@@ -82583,7 +83801,7 @@ function doLogs(follow, lines) {
82583
83801
  setInterval(() => {
82584
83802
  }, 6e4);
82585
83803
  } else {
82586
- const content = fs22.readFileSync(logFile, "utf-8");
83804
+ const content = fs23.readFileSync(logFile, "utf-8");
82587
83805
  const allLines = content.split("\n");
82588
83806
  const tail = allLines.slice(-lines);
82589
83807
  console.log(tail.join("\n"));
@@ -84163,7 +85381,7 @@ __export(dashboard_exports, {
84163
85381
  default: () => dashboard_default
84164
85382
  });
84165
85383
  import { fileURLToPath as fileURLToPath6 } from "url";
84166
- import path34 from "path";
85384
+ import path35 from "path";
84167
85385
  var dashboard_default;
84168
85386
  var init_dashboard = __esm({
84169
85387
  "src/cli/commands/dashboard.ts"() {
@@ -84193,8 +85411,8 @@ var init_dashboard = __esm({
84193
85411
  }
84194
85412
  const dataDir = await getProjectDataDir2(project.id);
84195
85413
  const port = parseInt(args.port, 10) || 3210;
84196
- const cliDir = path34.dirname(fileURLToPath6(import.meta.url));
84197
- const staticDir = path34.join(cliDir, "..", "dashboard", "static");
85414
+ const cliDir = path35.dirname(fileURLToPath6(import.meta.url));
85415
+ const staticDir = path35.join(cliDir, "..", "dashboard", "static");
84198
85416
  await startDashboard2(dataDir, port, staticDir, project.id, project.name, true, void 0, project.rootPath, true);
84199
85417
  await new Promise(() => {
84200
85418
  });
@@ -84450,12 +85668,12 @@ var uninstall_exports = {};
84450
85668
  __export(uninstall_exports, {
84451
85669
  default: () => uninstall_default
84452
85670
  });
84453
- import * as fs23 from "fs";
84454
- import * as path35 from "path";
85671
+ import * as fs24 from "fs";
85672
+ import * as path36 from "path";
84455
85673
  import * as os4 from "os";
84456
85674
  function exists(p2) {
84457
85675
  try {
84458
- fs23.accessSync(p2);
85676
+ fs24.accessSync(p2);
84459
85677
  return true;
84460
85678
  } catch {
84461
85679
  return false;
@@ -84464,7 +85682,7 @@ function exists(p2) {
84464
85682
  function checkJSON(p2) {
84465
85683
  if (!exists(p2)) return false;
84466
85684
  try {
84467
- const content = fs23.readFileSync(p2, "utf-8");
85685
+ const content = fs24.readFileSync(p2, "utf-8");
84468
85686
  const cfg = JSON.parse(content);
84469
85687
  const servers = cfg.mcpServers ?? cfg.mcp_servers ?? cfg.servers ?? {};
84470
85688
  return Object.keys(servers).some((k5) => k5.toLowerCase().includes("memorix"));
@@ -84475,7 +85693,7 @@ function checkJSON(p2) {
84475
85693
  function checkTOML(p2) {
84476
85694
  if (!exists(p2)) return false;
84477
85695
  try {
84478
- const content = fs23.readFileSync(p2, "utf-8");
85696
+ const content = fs24.readFileSync(p2, "utf-8");
84479
85697
  return /\[mcp_servers\.(?:memorix|Memorix)\]/.test(content);
84480
85698
  } catch {
84481
85699
  return false;
@@ -84485,124 +85703,124 @@ function getMCPConfigEntries(home, cwd) {
84485
85703
  const entries = [];
84486
85704
  entries.push({
84487
85705
  agent: "Claude Code",
84488
- path: path35.join(home, ".claude.json"),
85706
+ path: path36.join(home, ".claude.json"),
84489
85707
  kind: "global",
84490
85708
  format: "json",
84491
- detected: checkJSON(path35.join(home, ".claude.json")),
85709
+ detected: checkJSON(path36.join(home, ".claude.json")),
84492
85710
  note: 'Remove the "memorix" key from mcpServers in this file.'
84493
85711
  });
84494
85712
  entries.push({
84495
85713
  agent: "Claude Code",
84496
- path: path35.join(cwd, ".claude", "settings.json"),
85714
+ path: path36.join(cwd, ".claude", "settings.json"),
84497
85715
  kind: "project",
84498
85716
  format: "json",
84499
- detected: checkJSON(path35.join(cwd, ".claude", "settings.json")),
85717
+ detected: checkJSON(path36.join(cwd, ".claude", "settings.json")),
84500
85718
  note: 'Remove the "memorix" key from mcpServers in this file.'
84501
85719
  });
84502
85720
  entries.push({
84503
85721
  agent: "Cursor",
84504
- path: path35.join(home, ".cursor", "mcp.json"),
85722
+ path: path36.join(home, ".cursor", "mcp.json"),
84505
85723
  kind: "global",
84506
85724
  format: "json",
84507
- detected: checkJSON(path35.join(home, ".cursor", "mcp.json")),
85725
+ detected: checkJSON(path36.join(home, ".cursor", "mcp.json")),
84508
85726
  note: 'Remove the "memorix" key from mcpServers in this file.'
84509
85727
  });
84510
85728
  entries.push({
84511
85729
  agent: "Cursor",
84512
- path: path35.join(cwd, ".cursor", "mcp.json"),
85730
+ path: path36.join(cwd, ".cursor", "mcp.json"),
84513
85731
  kind: "project",
84514
85732
  format: "json",
84515
- detected: checkJSON(path35.join(cwd, ".cursor", "mcp.json")),
85733
+ detected: checkJSON(path36.join(cwd, ".cursor", "mcp.json")),
84516
85734
  note: 'Remove the "memorix" key from mcpServers in this file.'
84517
85735
  });
84518
85736
  entries.push({
84519
85737
  agent: "Windsurf",
84520
- path: path35.join(home, ".codeium", "windsurf", "mcp_config.json"),
85738
+ path: path36.join(home, ".codeium", "windsurf", "mcp_config.json"),
84521
85739
  kind: "global",
84522
85740
  format: "json",
84523
- detected: checkJSON(path35.join(home, ".codeium", "windsurf", "mcp_config.json")),
85741
+ detected: checkJSON(path36.join(home, ".codeium", "windsurf", "mcp_config.json")),
84524
85742
  note: 'Remove the "memorix" key from mcpServers in this file.'
84525
85743
  });
84526
85744
  entries.push({
84527
85745
  agent: "Codex",
84528
- path: path35.join(home, ".codex", "config.toml"),
85746
+ path: path36.join(home, ".codex", "config.toml"),
84529
85747
  kind: "global",
84530
85748
  format: "toml",
84531
- detected: checkTOML(path35.join(home, ".codex", "config.toml")),
85749
+ detected: checkTOML(path36.join(home, ".codex", "config.toml")),
84532
85750
  note: "Remove the [mcp_servers.memorix] section from this file."
84533
85751
  });
84534
85752
  entries.push({
84535
85753
  agent: "VS Code / Copilot",
84536
- path: path35.join(home, ".vscode", "mcp.json"),
85754
+ path: path36.join(home, ".vscode", "mcp.json"),
84537
85755
  kind: "global",
84538
85756
  format: "json",
84539
- detected: checkJSON(path35.join(home, ".vscode", "mcp.json")),
85757
+ detected: checkJSON(path36.join(home, ".vscode", "mcp.json")),
84540
85758
  note: 'Remove the "memorix" key from servers in this file.'
84541
85759
  });
84542
85760
  entries.push({
84543
85761
  agent: "VS Code / Copilot",
84544
- path: path35.join(cwd, ".vscode", "mcp.json"),
85762
+ path: path36.join(cwd, ".vscode", "mcp.json"),
84545
85763
  kind: "project",
84546
85764
  format: "json",
84547
- detected: checkJSON(path35.join(cwd, ".vscode", "mcp.json")),
85765
+ detected: checkJSON(path36.join(cwd, ".vscode", "mcp.json")),
84548
85766
  note: 'Remove the "memorix" key from servers in this file.'
84549
85767
  });
84550
85768
  entries.push({
84551
85769
  agent: "Kiro",
84552
- path: path35.join(home, ".kiro", "settings", "mcp.json"),
85770
+ path: path36.join(home, ".kiro", "settings", "mcp.json"),
84553
85771
  kind: "global",
84554
85772
  format: "json",
84555
- detected: checkJSON(path35.join(home, ".kiro", "settings", "mcp.json")),
85773
+ detected: checkJSON(path36.join(home, ".kiro", "settings", "mcp.json")),
84556
85774
  note: 'Remove the "memorix" key from mcpServers in this file.'
84557
85775
  });
84558
85776
  entries.push({
84559
85777
  agent: "Kiro",
84560
- path: path35.join(cwd, ".kiro", "settings", "mcp.json"),
85778
+ path: path36.join(cwd, ".kiro", "settings", "mcp.json"),
84561
85779
  kind: "project",
84562
85780
  format: "json",
84563
- detected: checkJSON(path35.join(cwd, ".kiro", "settings", "mcp.json")),
85781
+ detected: checkJSON(path36.join(cwd, ".kiro", "settings", "mcp.json")),
84564
85782
  note: 'Remove the "memorix" key from mcpServers in this file.'
84565
85783
  });
84566
85784
  entries.push({
84567
85785
  agent: "Gemini CLI",
84568
- path: path35.join(home, ".gemini", "settings.json"),
85786
+ path: path36.join(home, ".gemini", "settings.json"),
84569
85787
  kind: "global",
84570
85788
  format: "json",
84571
- detected: checkJSON(path35.join(home, ".gemini", "settings.json")),
85789
+ detected: checkJSON(path36.join(home, ".gemini", "settings.json")),
84572
85790
  note: 'Remove the "memorix" key from mcpServers in this file.'
84573
85791
  });
84574
85792
  entries.push({
84575
85793
  agent: "Antigravity",
84576
- path: path35.join(home, ".gemini", "config", "mcp_config.json"),
85794
+ path: path36.join(home, ".gemini", "config", "mcp_config.json"),
84577
85795
  kind: "global",
84578
85796
  format: "json",
84579
- detected: checkJSON(path35.join(home, ".gemini", "config", "mcp_config.json")),
85797
+ detected: checkJSON(path36.join(home, ".gemini", "config", "mcp_config.json")),
84580
85798
  note: 'Remove the "memorix" key from mcpServers in this file.'
84581
85799
  });
84582
85800
  entries.push({
84583
85801
  agent: "Antigravity",
84584
- path: path35.join(home, ".gemini", "config", "hooks.json"),
85802
+ path: path36.join(home, ".gemini", "config", "hooks.json"),
84585
85803
  kind: "global",
84586
85804
  format: "json",
84587
- detected: exists(path35.join(home, ".gemini", "config", "hooks.json")),
85805
+ detected: exists(path36.join(home, ".gemini", "config", "hooks.json")),
84588
85806
  note: 'Remove the "memorix" hook group from this file.'
84589
85807
  });
84590
85808
  entries.push({
84591
85809
  agent: "Antigravity",
84592
- path: path35.join(home, ".gemini", "config", "plugins", "memorix", "plugin.json"),
85810
+ path: path36.join(home, ".gemini", "config", "plugins", "memorix", "plugin.json"),
84593
85811
  kind: "global",
84594
85812
  format: "json",
84595
- detected: exists(path35.join(home, ".gemini", "config", "plugins", "memorix", "plugin.json")),
85813
+ detected: exists(path36.join(home, ".gemini", "config", "plugins", "memorix", "plugin.json")),
84596
85814
  note: "Delete the containing ~/.gemini/config/plugins/memorix plugin directory if you want to remove the Antigravity plugin package."
84597
85815
  });
84598
85816
  const traeCfg = (() => {
84599
85817
  if (process.platform === "win32") {
84600
- return path35.join(process.env.APPDATA || path35.join(home, "AppData", "Roaming"), "Trae", "User", "mcp.json");
85818
+ return path36.join(process.env.APPDATA || path36.join(home, "AppData", "Roaming"), "Trae", "User", "mcp.json");
84601
85819
  }
84602
85820
  if (process.platform === "darwin") {
84603
- return path35.join(home, "Library", "Application Support", "Trae", "User", "mcp.json");
85821
+ return path36.join(home, "Library", "Application Support", "Trae", "User", "mcp.json");
84604
85822
  }
84605
- return path35.join(home, ".config", "Trae", "User", "mcp.json");
85823
+ return path36.join(home, ".config", "Trae", "User", "mcp.json");
84606
85824
  })();
84607
85825
  entries.push({
84608
85826
  agent: "Trae",
@@ -84615,9 +85833,9 @@ function getMCPConfigEntries(home, cwd) {
84615
85833
  return entries;
84616
85834
  }
84617
85835
  function checkBackground(home) {
84618
- const statePath = path35.join(home, ".memorix", "background.json");
85836
+ const statePath = path36.join(home, ".memorix", "background.json");
84619
85837
  try {
84620
- const data = fs23.readFileSync(statePath, "utf-8");
85838
+ const data = fs24.readFileSync(statePath, "utf-8");
84621
85839
  const state = JSON.parse(data);
84622
85840
  try {
84623
85841
  process.kill(state.pid, 0);
@@ -84756,7 +85974,7 @@ var init_uninstall = __esm({
84756
85974
  },
84757
85975
  async run({ args }) {
84758
85976
  const home = os4.homedir();
84759
- const memorixDir = path35.join(home, ".memorix");
85977
+ const memorixDir = path36.join(home, ".memorix");
84760
85978
  const dryRun = args["dry-run"];
84761
85979
  const yes = args.yes;
84762
85980
  const doHooks = args.hooks;
@@ -84884,7 +86102,7 @@ var init_uninstall = __esm({
84884
86102
  if (exists(memorixDir)) {
84885
86103
  console.log(`[DELETE] Removing ${memorixDir}...`);
84886
86104
  try {
84887
- fs23.rmSync(memorixDir, { recursive: true, force: true });
86105
+ fs24.rmSync(memorixDir, { recursive: true, force: true });
84888
86106
  console.log("[OK] Data directory deleted.");
84889
86107
  changes++;
84890
86108
  } catch (err) {
@@ -85255,24 +86473,24 @@ var init_claude_stream = __esm({
85255
86473
  });
85256
86474
 
85257
86475
  // src/orchestrate/adapters/claude.ts
85258
- import * as fs24 from "fs";
85259
- import * as path36 from "path";
86476
+ import * as fs25 from "fs";
86477
+ import * as path37 from "path";
85260
86478
  function resolveMcpConfigPath(projectDir2) {
85261
- const localPath = path36.join(projectDir2, ".claude", "settings.local.json");
86479
+ const localPath = path37.join(projectDir2, ".claude", "settings.local.json");
85262
86480
  try {
85263
- if (fs24.existsSync(localPath)) return localPath;
86481
+ if (fs25.existsSync(localPath)) return localPath;
85264
86482
  } catch {
85265
86483
  }
85266
- const settingsPath = path36.join(projectDir2, ".claude", "settings.json");
86484
+ const settingsPath = path37.join(projectDir2, ".claude", "settings.json");
85267
86485
  try {
85268
- if (fs24.existsSync(settingsPath)) return settingsPath;
86486
+ if (fs25.existsSync(settingsPath)) return settingsPath;
85269
86487
  } catch {
85270
86488
  }
85271
86489
  const mcpConfig = {
85272
86490
  mcpServers: {
85273
86491
  memorix: {
85274
86492
  command: process.execPath,
85275
- args: [path36.resolve(path36.dirname(process.execPath), "..", "lib", "node_modules", "memorix", "dist", "index.js"), "serve", "--transport", "stdio"]
86493
+ args: [path37.resolve(path37.dirname(process.execPath), "..", "lib", "node_modules", "memorix", "dist", "index.js"), "serve", "--transport", "stdio"]
85276
86494
  }
85277
86495
  }
85278
86496
  };
@@ -85282,10 +86500,10 @@ function resolveMcpConfigPath(projectDir2) {
85282
86500
  args: ["serve", "--transport", "stdio"]
85283
86501
  };
85284
86502
  try {
85285
- const claudeDir = path36.join(projectDir2, ".claude");
85286
- fs24.mkdirSync(claudeDir, { recursive: true });
85287
- const tempPath = path36.join(claudeDir, "settings.local.json");
85288
- fs24.writeFileSync(tempPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
86503
+ const claudeDir = path37.join(projectDir2, ".claude");
86504
+ fs25.mkdirSync(claudeDir, { recursive: true });
86505
+ const tempPath = path37.join(claudeDir, "settings.local.json");
86506
+ fs25.writeFileSync(tempPath, JSON.stringify(mcpConfig, null, 2), "utf-8");
85289
86507
  return tempPath;
85290
86508
  } catch {
85291
86509
  return null;
@@ -86701,9 +87919,9 @@ function writePipelineSummary(projectDir2, summary) {
86701
87919
  return null;
86702
87920
  }
86703
87921
  }
86704
- function safeWrite(path37, content) {
87922
+ function safeWrite(path38, content) {
86705
87923
  try {
86706
- writeFileSync9(path37, content, "utf-8");
87924
+ writeFileSync9(path38, content, "utf-8");
86707
87925
  } catch {
86708
87926
  }
86709
87927
  }
@@ -88174,8 +89392,8 @@ var init_orchestrate = __esm({
88174
89392
  const { getProjectDataDir: getProjectDataDir2 } = await Promise.resolve().then(() => (init_persistence(), persistence_exports));
88175
89393
  const { resolveAdapters: resolveAdapters2, parseAgentQuotas: parseAgentQuotas2, buildQuotaMap: buildQuotaMap2 } = await Promise.resolve().then(() => (init_adapters(), adapters_exports));
88176
89394
  const { runCoordinationLoop: runCoordinationLoop2 } = await Promise.resolve().then(() => (init_coordinator(), coordinator_exports));
88177
- const path37 = await import("path");
88178
- const projectDir2 = args.project ? path37.resolve(args.project) : process.cwd();
89395
+ const path38 = await import("path");
89396
+ const projectDir2 = args.project ? path38.resolve(args.project) : process.cwd();
88179
89397
  const proj = detectProject2(projectDir2);
88180
89398
  if (!proj) {
88181
89399
  console.error("[ERROR] Not a git repository. Run `git init` first.");
@@ -89285,7 +90503,7 @@ var init_Panels = __esm({
89285
90503
  // src/cli/tui/ConfigureView.tsx
89286
90504
  import { useState as useState2, useEffect as useEffect2 } from "react";
89287
90505
  import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
89288
- import * as fs25 from "fs";
90506
+ import * as fs26 from "fs";
89289
90507
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
89290
90508
  function getConfigPath() {
89291
90509
  return `${process.env.HOME || process.env.USERPROFILE}/.memorix/config.json`;
@@ -89293,15 +90511,15 @@ function getConfigPath() {
89293
90511
  function loadConfig() {
89294
90512
  try {
89295
90513
  const p2 = getConfigPath();
89296
- if (fs25.existsSync(p2)) return JSON.parse(fs25.readFileSync(p2, "utf-8"));
90514
+ if (fs26.existsSync(p2)) return JSON.parse(fs26.readFileSync(p2, "utf-8"));
89297
90515
  } catch {
89298
90516
  }
89299
90517
  return {};
89300
90518
  }
89301
90519
  function saveConfig(config2) {
89302
90520
  const dir = `${process.env.HOME || process.env.USERPROFILE}/.memorix`;
89303
- if (!fs25.existsSync(dir)) fs25.mkdirSync(dir, { recursive: true });
89304
- fs25.writeFileSync(getConfigPath(), JSON.stringify(config2, null, 2));
90521
+ if (!fs26.existsSync(dir)) fs26.mkdirSync(dir, { recursive: true });
90522
+ fs26.writeFileSync(getConfigPath(), JSON.stringify(config2, null, 2));
89305
90523
  }
89306
90524
  function separator2(w3 = 50) {
89307
90525
  return SEP.thin.repeat(w3);
@@ -90014,7 +91232,7 @@ var init_session_service = __esm({
90014
91232
  });
90015
91233
 
90016
91234
  // src/cli/tui/data.ts
90017
- import * as fs26 from "fs";
91235
+ import * as fs27 from "fs";
90018
91236
  function formatSearchModeLabel(mode) {
90019
91237
  const normalized = (mode || "").toLowerCase();
90020
91238
  if (!normalized) return "Unknown";
@@ -90221,7 +91439,7 @@ async function getBackgroundStatus() {
90221
91439
  try {
90222
91440
  const home = process.env.HOME || process.env.USERPROFILE || "";
90223
91441
  const statePath = `${home.replace(/\\/g, "/")}/.memorix/background.json`;
90224
- if (!fs26.existsSync(statePath)) {
91442
+ if (!fs27.existsSync(statePath)) {
90225
91443
  try {
90226
91444
  const controller = new AbortController();
90227
91445
  const timer = setTimeout(() => controller.abort(), 2e3);
@@ -90242,7 +91460,7 @@ async function getBackgroundStatus() {
90242
91460
  }
90243
91461
  return result;
90244
91462
  }
90245
- const state = JSON.parse(fs26.readFileSync(statePath, "utf-8"));
91463
+ const state = JSON.parse(fs27.readFileSync(statePath, "utf-8"));
90246
91464
  result.pid = state.pid;
90247
91465
  result.port = state.port;
90248
91466
  result.startedAt = state.startedAt;
@@ -90333,8 +91551,8 @@ function detectMode() {
90333
91551
  try {
90334
91552
  const home = process.env.HOME || process.env.USERPROFILE || "";
90335
91553
  const statePath = `${home.replace(/\\/g, "/")}/.memorix/background.json`;
90336
- if (fs26.existsSync(statePath)) {
90337
- const state = JSON.parse(fs26.readFileSync(statePath, "utf-8"));
91554
+ if (fs27.existsSync(statePath)) {
91555
+ const state = JSON.parse(fs27.readFileSync(statePath, "utf-8"));
90338
91556
  try {
90339
91557
  process.kill(state.pid, 0);
90340
91558
  return { mode: "Background", detail: `port ${state.port}` };
@@ -92875,9 +94093,17 @@ var GUIDES = {
92875
94093
  "memorix memory recent [--limit 10]",
92876
94094
  "memorix memory resolve --ids 42,43 [--status resolved|archived]",
92877
94095
  "memorix memory consolidate --action preview|execute",
92878
- 'memorix memory promote --ids 42,43 [--trigger "..."] [--instruction "..."]'
94096
+ 'memorix memory promote --ids 42,43 [--trigger "..."] [--instruction "..."]',
94097
+ "memorix memory long-term list [--all]",
94098
+ 'memorix memory long-term add --kind semantic --scope user --portability portable --title "..." --text "..." [--tags "..."] [--applicability "..."]',
94099
+ "memorix memory long-term promote --from-observation 42 --kind procedural --scope project",
94100
+ 'memorix memory long-term qualify|approve|archive --id <id> --reason "..."',
94101
+ 'memorix memory long-term supersede --id <old-id> --superseded-by <qualified-id> --reason "..."'
92879
94102
  ],
92880
- notes: ["Personal and team visibility require `memorix identity join` or `memorix identity use` first."]
94103
+ notes: [
94104
+ "Personal and team visibility require `memorix identity join` or `memorix identity use` first.",
94105
+ "Candidates never enter a task Workset. Only manual or user-confirmed `user + portable` memory may cross local projects."
94106
+ ]
92881
94107
  },
92882
94108
  identity: {
92883
94109
  summary: "Select the active local actor for private memory and coordination commands.",