memorix 1.2.9 → 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 (68) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +30 -4
  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 +1945 -579
  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 +24 -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 +5 -3
  23. package/docs/API_REFERENCE.md +20 -1
  24. package/docs/ARCHITECTURE.md +34 -1
  25. package/docs/DEVELOPMENT.md +10 -3
  26. package/docs/INTEGRATIONS.md +1 -1
  27. package/docs/MODULES.md +27 -1
  28. package/docs/README.md +3 -3
  29. package/docs/SETUP.md +6 -4
  30. package/docs/dev-log/progress.txt +22 -0
  31. package/docs/hooks-architecture.md +1 -1
  32. package/llms-full.txt +5 -1
  33. package/llms.txt +2 -0
  34. package/package.json +7 -2
  35. package/plugins/antigravity/memorix/rules/memorix.md +2 -0
  36. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  37. package/plugins/claude/memorix/skills/memorix-memory/SKILL.md +3 -0
  38. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  39. package/plugins/codex/memorix/skills/memorix-memory/SKILL.md +3 -0
  40. package/plugins/copilot/memorix/plugin.json +1 -1
  41. package/plugins/copilot/memorix/skills/memorix-memory/SKILL.md +3 -0
  42. package/plugins/cursor/memorix/skills/memorix-memory/SKILL.md +3 -0
  43. package/plugins/gemini/memorix/GEMINI.md +2 -0
  44. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  45. package/plugins/omp/memorix/package.json +1 -1
  46. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  47. package/plugins/pi/memorix/package.json +1 -1
  48. package/plugins/pi/memorix/skills/memorix-memory/SKILL.md +3 -0
  49. package/server.json +38 -0
  50. package/src/cli/command-guide.ts +9 -1
  51. package/src/cli/commands/agent-integrations.ts +12 -6
  52. package/src/cli/commands/codegraph.ts +1 -0
  53. package/src/cli/commands/memory.ts +217 -1
  54. package/src/cli/commands/setup.ts +200 -23
  55. package/src/codegraph/auto-context.ts +11 -0
  56. package/src/codegraph/context-pack.ts +3 -0
  57. package/src/embedding/api-provider.ts +23 -9
  58. package/src/embedding/provider.ts +21 -10
  59. package/src/hooks/installers/index.ts +2 -0
  60. package/src/knowledge/context-assembly.ts +2 -1
  61. package/src/knowledge/workset.ts +77 -4
  62. package/src/memory/long-term-store.ts +242 -0
  63. package/src/memory/long-term-types.ts +136 -0
  64. package/src/memory/long-term.ts +626 -0
  65. package/src/memory/owner.ts +75 -0
  66. package/src/server.ts +112 -30
  67. package/src/store/sqlite-db.ts +74 -0
  68. 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.9" : 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
  }
@@ -35531,6 +36622,8 @@ __export(setup_exports, {
35531
36622
  installOpenClawBundlePackage: () => installOpenClawBundlePackage,
35532
36623
  installPiPackage: () => installPiPackage,
35533
36624
  installPluginPackage: () => installPluginPackage,
36625
+ migrateLegacyCodexIntegration: () => migrateLegacyCodexIntegration,
36626
+ parseCodexPluginState: () => parseCodexPluginState,
35534
36627
  removeLegacyCodexMemorixMcpConfig: () => removeLegacyCodexMemorixMcpConfig,
35535
36628
  tryInstallCodexPlugin: () => tryInstallCodexPlugin
35536
36629
  });
@@ -35539,7 +36632,7 @@ import { existsSync as existsSync12 } from "fs";
35539
36632
  import { copyFile, mkdir as mkdir5, readFile as readFile5, readdir as readdir2, rm, writeFile as writeFile5 } from "fs/promises";
35540
36633
  import { createRequire as createRequire5 } from "module";
35541
36634
  import { homedir as homedir24 } from "os";
35542
- import path23 from "path";
36635
+ import path24 from "path";
35543
36636
  import { fileURLToPath as fileURLToPath5 } from "url";
35544
36637
  function getSetupAgentTargets() {
35545
36638
  return [...SUPPORTED_SETUP_AGENTS];
@@ -35576,13 +36669,13 @@ function buildSetupPlan(options2) {
35576
36669
  if (!isPackageOwnedAgent && includeHooks) actions.push("hooks");
35577
36670
  return { agent: options2.agent, mcp, actions, includeHooks, includeRules, includePlugin: wantsPlugin };
35578
36671
  }
35579
- function findPackageRoot(start = path23.dirname(fileURLToPath5(import.meta.url))) {
36672
+ function findPackageRoot(start = path24.dirname(fileURLToPath5(import.meta.url))) {
35580
36673
  let dir = start;
35581
36674
  for (let i2 = 0; i2 < 8; i2++) {
35582
- 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"))) {
35583
36676
  return dir;
35584
36677
  }
35585
- const parent = path23.dirname(dir);
36678
+ const parent = path24.dirname(dir);
35586
36679
  if (parent === dir) break;
35587
36680
  dir = parent;
35588
36681
  }
@@ -35593,12 +36686,12 @@ async function copyDir(source, destination) {
35593
36686
  await mkdir5(destination, { recursive: true });
35594
36687
  const entries = await readdir2(source, { withFileTypes: true });
35595
36688
  for (const entry of entries) {
35596
- const src2 = path23.join(source, entry.name);
35597
- const dest = path23.join(destination, entry.name);
36689
+ const src2 = path24.join(source, entry.name);
36690
+ const dest = path24.join(destination, entry.name);
35598
36691
  if (entry.isDirectory()) {
35599
36692
  await copyDir(src2, dest);
35600
36693
  } else {
35601
- await mkdir5(path23.dirname(dest), { recursive: true });
36694
+ await mkdir5(path24.dirname(dest), { recursive: true });
35602
36695
  await copyFile(src2, dest);
35603
36696
  }
35604
36697
  }
@@ -35606,16 +36699,16 @@ async function copyDir(source, destination) {
35606
36699
  async function writeOfficialSkills(skillsRoot) {
35607
36700
  const written = [];
35608
36701
  for (const skill2 of OFFICIAL_MEMORIX_SKILLS) {
35609
- const skillPath = path23.join(skillsRoot, skill2.name, "SKILL.md");
35610
- 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 });
35611
36704
  await writeFile5(skillPath, skill2.content, "utf-8");
35612
36705
  written.push(skillPath);
35613
36706
  }
35614
36707
  return written;
35615
36708
  }
35616
36709
  async function stripHookCaptureFromPlugin(pluginPath, agent) {
35617
- await rm(path23.join(pluginPath, "hooks"), { recursive: true, force: true });
35618
- 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");
35619
36712
  try {
35620
36713
  const manifest = JSON.parse(await readFile5(manifestPath, "utf-8"));
35621
36714
  delete manifest.hooks;
@@ -35631,7 +36724,7 @@ async function stripHookCaptureFromPlugin(pluginPath, agent) {
35631
36724
  }
35632
36725
  }
35633
36726
  async function stampCodexPluginVersion(pluginPath) {
35634
- const manifestPath = path23.join(pluginPath, ".codex-plugin", "plugin.json");
36727
+ const manifestPath = path24.join(pluginPath, ".codex-plugin", "plugin.json");
35635
36728
  const manifest = JSON.parse(await readFile5(manifestPath, "utf-8"));
35636
36729
  if (manifest.name !== "memorix") {
35637
36730
  throw new Error(`Unexpected Codex plugin manifest at ${manifestPath}`);
@@ -35641,8 +36734,8 @@ async function stampCodexPluginVersion(pluginPath) {
35641
36734
  `, "utf-8");
35642
36735
  }
35643
36736
  async function stripHookCaptureFromOpenClawBundle(bundlePath) {
35644
- await rm(path23.join(bundlePath, "hooks"), { recursive: true, force: true });
35645
- 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");
35646
36739
  try {
35647
36740
  const manifest = JSON.parse(await readFile5(manifestPath, "utf-8"));
35648
36741
  delete manifest.hooks;
@@ -35678,7 +36771,7 @@ function mergeHermesPluginEnabled(existingContent, pluginName) {
35678
36771
  }, { lineWidth: -1 });
35679
36772
  }
35680
36773
  function relativePosix(from, to) {
35681
- let rel = path23.relative(from, to).replace(/\\/g, "/");
36774
+ let rel = path24.relative(from, to).replace(/\\/g, "/");
35682
36775
  if (!rel.startsWith("./") && !rel.startsWith("../")) rel = `./${rel}`;
35683
36776
  return rel;
35684
36777
  }
@@ -35779,6 +36872,21 @@ function mergeTomlMcpConfig(existingContent, generatedContent) {
35779
36872
  return `${parts.join("\n\n")}
35780
36873
  `;
35781
36874
  }
36875
+ function getTomlSection(content, section) {
36876
+ const lines = content.split(/\r?\n/);
36877
+ const header = `[${section}]`;
36878
+ const start = lines.findIndex((line) => line.trim() === header);
36879
+ if (start < 0) return null;
36880
+ let end = lines.length;
36881
+ for (let index = start + 1; index < lines.length; index += 1) {
36882
+ const trimmed = lines[index].trim();
36883
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
36884
+ end = index;
36885
+ break;
36886
+ }
36887
+ }
36888
+ return lines.slice(start + 1, end).join("\n");
36889
+ }
35782
36890
  function isLegacyCodexMemorixNodeServer(server) {
35783
36891
  if (server.name !== "memorix" || server.command.trim().toLowerCase() !== "node") return false;
35784
36892
  const startsMemorixStdio = server.args.some((arg) => arg.trim().toLowerCase() === "serve");
@@ -35788,22 +36896,102 @@ function isLegacyCodexMemorixNodeServer(server) {
35788
36896
  });
35789
36897
  return startsMemorixStdio && sourceEntry;
35790
36898
  }
35791
- async function removeLegacyCodexMemorixMcpConfig(configPath = path23.join(homedir24(), ".codex", "config.toml")) {
36899
+ function isOwnedLegacyCodexMcp(content) {
36900
+ const section = getTomlSection(content, "mcp_servers.memorix");
36901
+ if (section === null || getTomlSection(content, "mcp_servers.memorix.env") !== null) return false;
36902
+ const allowedKeys = /* @__PURE__ */ new Set(["command", "args", "type", "startup_timeout_sec", "tool_timeout_sec", "enabled"]);
36903
+ for (const rawLine of section.split(/\r?\n/)) {
36904
+ const line = rawLine.trim();
36905
+ if (!line || line.startsWith("#")) continue;
36906
+ const key = line.match(/^([A-Za-z0-9_]+)\s*=/)?.[1];
36907
+ if (!key || !allowedKeys.has(key)) return false;
36908
+ }
36909
+ const server = new CodexMCPAdapter().parse(content).find((entry) => entry.name === "memorix");
36910
+ return Boolean(server && isLegacyCodexMemorixNodeServer(server));
36911
+ }
36912
+ async function removeLegacyCodexMemorixMcpConfig(configPath = path24.join(homedir24(), ".codex", "config.toml")) {
35792
36913
  let existingContent;
35793
36914
  try {
35794
36915
  existingContent = await readFile5(configPath, "utf-8");
35795
36916
  } catch {
35796
36917
  return { configPath, removed: false };
35797
36918
  }
35798
- const adapter = new CodexMCPAdapter();
35799
- const legacyServer = adapter.parse(existingContent).find(isLegacyCodexMemorixNodeServer);
35800
- if (!legacyServer) return { configPath, removed: false };
36919
+ if (!isOwnedLegacyCodexMcp(existingContent)) return { configPath, removed: false };
35801
36920
  let nextContent = removeTomlSection(existingContent, "mcp_servers.memorix.env");
35802
36921
  nextContent = removeTomlSection(nextContent, "mcp_servers.memorix");
35803
36922
  await writeFile5(configPath, nextContent ? `${nextContent}
35804
36923
  ` : "", "utf-8");
35805
36924
  return { configPath, removed: true };
35806
36925
  }
36926
+ function collectHookCommands(value, commands) {
36927
+ if (Array.isArray(value)) {
36928
+ for (const item of value) collectHookCommands(item, commands);
36929
+ return;
36930
+ }
36931
+ if (!value || typeof value !== "object") return;
36932
+ for (const [key, child] of Object.entries(value)) {
36933
+ if ((key === "command" || key === "commandWindows") && typeof child === "string") {
36934
+ commands.push(child);
36935
+ } else {
36936
+ collectHookCommands(child, commands);
36937
+ }
36938
+ }
36939
+ }
36940
+ function isOwnedLegacyCodexHooks(content) {
36941
+ try {
36942
+ const parsed = JSON.parse(content);
36943
+ if (!parsed.hooks || typeof parsed.hooks !== "object") return false;
36944
+ const commands = [];
36945
+ collectHookCommands(parsed.hooks, commands);
36946
+ return commands.length > 0 && commands.every((command) => /^memorix(?:\.cmd)?\s+hook(?:\s|$)/i.test(command.trim()));
36947
+ } catch {
36948
+ return false;
36949
+ }
36950
+ }
36951
+ async function removeOwnedLegacyCodexPluginFolder(homeDir) {
36952
+ const canonicalPath = path24.join(homeDir, "plugins", "memorix");
36953
+ const legacyPath = path24.join(homeDir, ".codex", "plugins", "memorix");
36954
+ if (!existsSync12(legacyPath)) return "missing";
36955
+ if (!existsSync12(canonicalPath)) return "preserved";
36956
+ try {
36957
+ const manifest = JSON.parse(await readFile5(path24.join(legacyPath, ".codex-plugin", "plugin.json"), "utf-8"));
36958
+ const repository = String(manifest.repository ?? "");
36959
+ if (manifest.name !== "memorix" || !repository.includes("github.com/AVIDS2/memorix")) return "preserved";
36960
+ await rm(legacyPath, { recursive: true, force: true });
36961
+ return "removed";
36962
+ } catch {
36963
+ return "preserved";
36964
+ }
36965
+ }
36966
+ async function migrateLegacyCodexIntegration(options2 = {}) {
36967
+ const homeDir = options2.homeDir ?? homedir24();
36968
+ const projectRoot = options2.projectRoot ?? process.cwd();
36969
+ const configPath = path24.join(homeDir, ".codex", "config.toml");
36970
+ let mcp = "missing";
36971
+ try {
36972
+ const content = await readFile5(configPath, "utf-8");
36973
+ if (getTomlSection(content, "mcp_servers.memorix") !== null) {
36974
+ mcp = (await removeLegacyCodexMemorixMcpConfig(configPath)).removed ? "removed" : "preserved";
36975
+ }
36976
+ } catch {
36977
+ mcp = "missing";
36978
+ }
36979
+ const hooksPath = path24.join(projectRoot, ".codex", "hooks.json");
36980
+ let projectHooks = "missing";
36981
+ try {
36982
+ const content = await readFile5(hooksPath, "utf-8");
36983
+ if (isOwnedLegacyCodexHooks(content)) {
36984
+ await rm(hooksPath, { force: true });
36985
+ projectHooks = "removed";
36986
+ } else {
36987
+ projectHooks = "preserved";
36988
+ }
36989
+ } catch {
36990
+ projectHooks = "missing";
36991
+ }
36992
+ const pluginFolder = await removeOwnedLegacyCodexPluginFolder(homeDir);
36993
+ return { mcp, projectHooks, pluginFolder };
36994
+ }
35807
36995
  function mergeYamlMcpConfig(existingContent, generatedContent) {
35808
36996
  let existing = {};
35809
36997
  try {
@@ -35848,12 +37036,12 @@ async function installMcpConfig(options2) {
35848
37036
  }
35849
37037
  const generated = adapter.generate([server]);
35850
37038
  const content = options2.agent === "codex" ? mergeTomlMcpConfig(existingContent, generated) : options2.agent === "hermes" ? mergeYamlMcpConfig(existingContent, generated) : mergeJsonMcpConfig(existingContent, generated);
35851
- await mkdir5(path23.dirname(configPath), { recursive: true });
37039
+ await mkdir5(path24.dirname(configPath), { recursive: true });
35852
37040
  await writeFile5(configPath, content, "utf-8");
35853
37041
  return { agent: options2.agent, configPath, transport: options2.mcp };
35854
37042
  }
35855
37043
  async function upsertCodexMarketplace(marketplacePath, pluginPath) {
35856
- await mkdir5(path23.dirname(marketplacePath), { recursive: true });
37044
+ await mkdir5(path24.dirname(marketplacePath), { recursive: true });
35857
37045
  let catalog;
35858
37046
  try {
35859
37047
  catalog = JSON.parse(await readFile5(marketplacePath, "utf-8"));
@@ -35866,9 +37054,9 @@ async function upsertCodexMarketplace(marketplacePath, pluginPath) {
35866
37054
  plugins: []
35867
37055
  };
35868
37056
  }
35869
- const marketplaceDir = path23.dirname(marketplacePath);
35870
- const agentsDir = path23.dirname(marketplaceDir);
35871
- 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;
35872
37060
  const sourcePath = relativePosix(marketplaceRoot, pluginPath);
35873
37061
  const entry = {
35874
37062
  name: "memorix",
@@ -35891,7 +37079,7 @@ async function upsertCodexMarketplace(marketplacePath, pluginPath) {
35891
37079
  await writeFile5(marketplacePath, JSON.stringify(catalog, null, 2) + "\n", "utf-8");
35892
37080
  }
35893
37081
  async function writeClaudeMarketplace(marketplacePath) {
35894
- await mkdir5(path23.dirname(marketplacePath), { recursive: true });
37082
+ await mkdir5(path24.dirname(marketplacePath), { recursive: true });
35895
37083
  const catalog = {
35896
37084
  $schema: "https://anthropic.com/claude-code/marketplace.schema.json",
35897
37085
  name: "memorix-local",
@@ -35920,18 +37108,18 @@ async function writeClaudeMarketplace(marketplacePath) {
35920
37108
  async function installPluginPackage(options2) {
35921
37109
  const home = options2.homeDir ?? homedir24();
35922
37110
  const packageRoot = findPackageRoot();
35923
- const source = path23.join(packageRoot, "plugins", options2.agent, "memorix");
37111
+ const source = path24.join(packageRoot, "plugins", options2.agent, "memorix");
35924
37112
  const includeHooks = options2.includeHooks ?? true;
35925
37113
  if (!existsSync12(source)) {
35926
37114
  throw new Error(`Plugin package template not found: ${source}`);
35927
37115
  }
35928
37116
  if (options2.agent === "codex") {
35929
- const pluginPath2 = path23.join(home, ".codex", "plugins", "memorix");
35930
- 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");
35931
37119
  await copyDir(source, pluginPath2);
35932
37120
  await stampCodexPluginVersion(pluginPath2);
35933
37121
  if (!includeHooks) await stripHookCaptureFromPlugin(pluginPath2, "codex");
35934
- await writeOfficialSkills(path23.join(pluginPath2, "skills"));
37122
+ await writeOfficialSkills(path24.join(pluginPath2, "skills"));
35935
37123
  await upsertCodexMarketplace(marketplacePath2, pluginPath2);
35936
37124
  return {
35937
37125
  agent: "codex",
@@ -35941,22 +37129,22 @@ async function installPluginPackage(options2) {
35941
37129
  };
35942
37130
  }
35943
37131
  if (options2.agent === "copilot") {
35944
- const pluginPath2 = path23.join(home, ".copilot", "plugins", "local", "memorix");
37132
+ const pluginPath2 = path24.join(home, ".copilot", "plugins", "local", "memorix");
35945
37133
  await copyDir(source, pluginPath2);
35946
37134
  if (!includeHooks) await stripHookCaptureFromPlugin(pluginPath2, "copilot");
35947
- await writeOfficialSkills(path23.join(pluginPath2, "skills"));
37135
+ await writeOfficialSkills(path24.join(pluginPath2, "skills"));
35948
37136
  return {
35949
37137
  agent: "copilot",
35950
37138
  pluginPath: pluginPath2,
35951
37139
  installHint: "Run `copilot plugin install <path>` if automatic install is unavailable, then restart Copilot CLI."
35952
37140
  };
35953
37141
  }
35954
- const marketplaceRoot = path23.join(home, ".claude", "plugins", "marketplaces", "memorix-local");
35955
- const marketplacePath = path23.join(marketplaceRoot, ".claude-plugin", "marketplace.json");
35956
- 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");
35957
37145
  await copyDir(source, pluginPath);
35958
37146
  if (!includeHooks) await stripHookCaptureFromPlugin(pluginPath, "claude");
35959
- await writeOfficialSkills(path23.join(pluginPath, "skills"));
37147
+ await writeOfficialSkills(path24.join(pluginPath, "skills"));
35960
37148
  await writeClaudeMarketplace(marketplacePath);
35961
37149
  return {
35962
37150
  agent: "claude",
@@ -35969,11 +37157,11 @@ async function installPluginPackage(options2) {
35969
37157
  async function installGeminiExtensionPackage(options2 = {}) {
35970
37158
  const home = options2.homeDir ?? homedir24();
35971
37159
  const packageRoot = findPackageRoot();
35972
- const source = path23.join(packageRoot, "plugins", "gemini", "memorix");
37160
+ const source = path24.join(packageRoot, "plugins", "gemini", "memorix");
35973
37161
  if (!existsSync12(source)) {
35974
37162
  throw new Error(`Gemini extension template not found: ${source}`);
35975
37163
  }
35976
- const extensionPath = path23.join(home, ".gemini", "extensions", "memorix");
37164
+ const extensionPath = path24.join(home, ".gemini", "extensions", "memorix");
35977
37165
  await copyDir(source, extensionPath);
35978
37166
  return {
35979
37167
  agent: "gemini-cli",
@@ -35983,16 +37171,16 @@ async function installGeminiExtensionPackage(options2 = {}) {
35983
37171
  }
35984
37172
  async function installAntigravityPluginPackage(options2 = {}) {
35985
37173
  const packageRoot = findPackageRoot();
35986
- const source = path23.join(packageRoot, "plugins", "antigravity", "memorix");
37174
+ const source = path24.join(packageRoot, "plugins", "antigravity", "memorix");
35987
37175
  if (!existsSync12(source)) {
35988
37176
  throw new Error(`Antigravity plugin template not found: ${source}`);
35989
37177
  }
35990
- 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");
35991
37179
  await copyDir(source, pluginPath);
35992
37180
  if (options2.includeHooks === false) {
35993
- await rm(path23.join(pluginPath, "hooks.json"), { force: true });
37181
+ await rm(path24.join(pluginPath, "hooks.json"), { force: true });
35994
37182
  }
35995
- await writeOfficialSkills(path23.join(pluginPath, "skills"));
37183
+ await writeOfficialSkills(path24.join(pluginPath, "skills"));
35996
37184
  return {
35997
37185
  agent: "antigravity",
35998
37186
  pluginPath,
@@ -36001,14 +37189,14 @@ async function installAntigravityPluginPackage(options2 = {}) {
36001
37189
  }
36002
37190
  async function installPiPackage(options2 = {}) {
36003
37191
  const packageRoot = findPackageRoot();
36004
- const source = path23.join(packageRoot, "plugins", "pi", "memorix");
37192
+ const source = path24.join(packageRoot, "plugins", "pi", "memorix");
36005
37193
  if (!existsSync12(source)) {
36006
37194
  throw new Error(`Pi package template not found: ${source}`);
36007
37195
  }
36008
- const defaultRoot = options2.global ? path23.join(options2.homeDir ?? homedir24(), ".pi", "agent", "packages") : path23.join(process.cwd(), ".pi", "packages");
36009
- 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");
36010
37198
  await copyDir(source, packagePath);
36011
- await writeOfficialSkills(path23.join(packagePath, "skills"));
37199
+ await writeOfficialSkills(path24.join(packagePath, "skills"));
36012
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.`;
36013
37201
  return {
36014
37202
  agent: "pi",
@@ -36019,14 +37207,14 @@ async function installPiPackage(options2 = {}) {
36019
37207
  async function installOpenClawBundlePackage(options2 = {}) {
36020
37208
  const home = options2.homeDir ?? homedir24();
36021
37209
  const packageRoot = findPackageRoot();
36022
- const source = path23.join(packageRoot, "plugins", "openclaw", "memorix");
37210
+ const source = path24.join(packageRoot, "plugins", "openclaw", "memorix");
36023
37211
  if (!existsSync12(source)) {
36024
37212
  throw new Error(`OpenClaw bundle template not found: ${source}`);
36025
37213
  }
36026
- const bundlePath = path23.join(home, ".openclaw", "extensions", "memorix");
37214
+ const bundlePath = path24.join(home, ".openclaw", "extensions", "memorix");
36027
37215
  await copyDir(source, bundlePath);
36028
37216
  if (options2.includeHooks === false) await stripHookCaptureFromOpenClawBundle(bundlePath);
36029
- await writeOfficialSkills(path23.join(bundlePath, "skills"));
37217
+ await writeOfficialSkills(path24.join(bundlePath, "skills"));
36030
37218
  return {
36031
37219
  agent: "openclaw",
36032
37220
  bundlePath,
@@ -36035,22 +37223,22 @@ async function installOpenClawBundlePackage(options2 = {}) {
36035
37223
  }
36036
37224
  async function installHermesPluginPackage(options2 = {}) {
36037
37225
  const packageRoot = findPackageRoot();
36038
- const source = path23.join(packageRoot, "plugins", "hermes", "memorix");
37226
+ const source = path24.join(packageRoot, "plugins", "hermes", "memorix");
36039
37227
  if (!existsSync12(source)) {
36040
37228
  throw new Error(`Hermes plugin template not found: ${source}`);
36041
37229
  }
36042
37230
  const hermesHome = resolveHermesHome(options2.homeDir);
36043
- const pluginPath = path23.join(hermesHome, "plugins", "memorix");
37231
+ const pluginPath = path24.join(hermesHome, "plugins", "memorix");
36044
37232
  await copyDir(source, pluginPath);
36045
- await writeOfficialSkills(path23.join(pluginPath, "skills"));
36046
- const configPath = path23.join(hermesHome, "config.yaml");
37233
+ await writeOfficialSkills(path24.join(pluginPath, "skills"));
37234
+ const configPath = path24.join(hermesHome, "config.yaml");
36047
37235
  let existingContent = null;
36048
37236
  try {
36049
37237
  existingContent = await readFile5(configPath, "utf-8");
36050
37238
  } catch {
36051
37239
  existingContent = null;
36052
37240
  }
36053
- await mkdir5(path23.dirname(configPath), { recursive: true });
37241
+ await mkdir5(path24.dirname(configPath), { recursive: true });
36054
37242
  await writeFile5(configPath, mergeHermesPluginEnabled(existingContent, "memorix"), "utf-8");
36055
37243
  return {
36056
37244
  agent: "hermes",
@@ -36062,14 +37250,14 @@ async function installHermesPluginPackage(options2 = {}) {
36062
37250
  }
36063
37251
  async function installOmpPackage(options2 = {}) {
36064
37252
  const packageRoot = findPackageRoot();
36065
- const source = path23.join(packageRoot, "plugins", "omp", "memorix");
37253
+ const source = path24.join(packageRoot, "plugins", "omp", "memorix");
36066
37254
  if (!existsSync12(source)) {
36067
37255
  throw new Error(`Oh-my-Pi package template not found: ${source}`);
36068
37256
  }
36069
- const defaultRoot = options2.global ? path23.join(options2.homeDir ?? homedir24(), ".omp", "agent", "packages") : path23.join(process.cwd(), ".omp", "packages");
36070
- 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");
36071
37259
  await copyDir(source, packagePath);
36072
- await writeOfficialSkills(path23.join(packagePath, "skills"));
37260
+ await writeOfficialSkills(path24.join(packagePath, "skills"));
36073
37261
  return {
36074
37262
  agent: "omp",
36075
37263
  packagePath,
@@ -36110,19 +37298,56 @@ ${install.stdout || ""}`.toLowerCase();
36110
37298
  message: installDetail ? `claude: marketplace registered, but automatic plugin install did not finish: ${installDetail}` : "claude: marketplace registered. Run `claude plugin install memorix@memorix-local`."
36111
37299
  };
36112
37300
  }
37301
+ function parseCodexPluginState(content) {
37302
+ try {
37303
+ const start = content.indexOf("{");
37304
+ const end = content.lastIndexOf("}");
37305
+ if (start < 0 || end < start) return "unknown";
37306
+ const parsed = JSON.parse(content.slice(start, end + 1));
37307
+ if (!Array.isArray(parsed.installed)) return "unknown";
37308
+ const plugin = parsed.installed.find((entry) => Boolean(entry) && typeof entry === "object" && entry.pluginId === "memorix@personal");
37309
+ if (!plugin || plugin.installed !== true) return "missing";
37310
+ return plugin.enabled === true ? "ready" : "disabled";
37311
+ } catch {
37312
+ return "unknown";
37313
+ }
37314
+ }
37315
+ function getCodexPluginState() {
37316
+ const result = spawnSync("codex", ["plugin", "list", "--json"], {
37317
+ encoding: "utf-8",
37318
+ stdio: "pipe",
37319
+ shell: process.platform === "win32"
37320
+ });
37321
+ if (result.status !== 0) return "unknown";
37322
+ return parseCodexPluginState(result.stdout || "");
37323
+ }
36113
37324
  function tryInstallCodexPlugin() {
36114
37325
  const result = spawnSync("codex", ["plugin", "add", "memorix@personal", "--json"], {
36115
37326
  encoding: "utf-8",
36116
37327
  stdio: "pipe",
36117
37328
  shell: process.platform === "win32"
36118
37329
  });
36119
- if (result.status === 0) {
36120
- return { ok: true, message: "codex: plugin installed from Personal marketplace" };
36121
- }
36122
37330
  const output = `${result.stderr || ""}
36123
37331
  ${result.stdout || ""}`.toLowerCase();
36124
- if (output.includes("already")) {
36125
- return { ok: true, message: "codex: plugin already installed from Personal marketplace" };
37332
+ const addFinished = result.status === 0 || output.includes("already");
37333
+ if (addFinished) {
37334
+ const pluginState = getCodexPluginState();
37335
+ if (pluginState === "ready") {
37336
+ return {
37337
+ ok: true,
37338
+ message: result.status === 0 ? "codex: plugin installed and enabled from Personal marketplace" : "codex: plugin already installed and enabled from Personal marketplace"
37339
+ };
37340
+ }
37341
+ if (pluginState === "disabled") {
37342
+ return {
37343
+ ok: false,
37344
+ message: "codex: Memorix plugin is installed but disabled. Enable it in Codex Plugins before any legacy MCP or project hooks are removed."
37345
+ };
37346
+ }
37347
+ return {
37348
+ ok: false,
37349
+ message: "codex: plugin registration finished, but Codex did not confirm an enabled Memorix plugin. Legacy MCP and project hooks were kept unchanged."
37350
+ };
36126
37351
  }
36127
37352
  const detail = (result.stderr || result.stdout || result.error?.message || "").trim();
36128
37353
  return {
@@ -36211,7 +37436,7 @@ ${hook.stdout || ""}`.toLowerCase();
36211
37436
  }
36212
37437
  function resolveHermesCommand(hermesHome) {
36213
37438
  if (process.platform === "win32") {
36214
- const localHermes = path23.join(hermesHome, "hermes-agent", "venv", "Scripts", "hermes.exe");
37439
+ const localHermes = path24.join(hermesHome, "hermes-agent", "venv", "Scripts", "hermes.exe");
36215
37440
  if (existsSync12(localHermes)) return localHermes;
36216
37441
  }
36217
37442
  return "hermes";
@@ -36268,14 +37493,14 @@ async function installAgentSetup(agent, plan, global2) {
36268
37493
  const hasAntigravityPlugin = plan.actions.includes("antigravity-plugin") && agent === "antigravity";
36269
37494
  const hasHermesPlugin = plan.actions.includes("hermes-plugin") && agent === "hermes";
36270
37495
  const hasOmpPackage = plan.actions.includes("omp-package") && agent === "omp";
36271
- const wantsMcpConfig = plan.mcp !== "none" && agent !== "pi";
37496
+ const wantsMcpConfig = plan.mcp !== "none" && agent !== "pi" && !(agent === "codex" && !global2);
36272
37497
  if (PLUGIN_PACKAGE_AGENTS.has(agent) && plan.includePlugin && !global2) {
36273
37498
  v3.info(`${agent}: project setup leaves user-level plugins untouched. Run \`memorix setup --agent ${agent} --global\` to install its plugin, skills, and lifecycle hooks.`);
36274
37499
  }
36275
37500
  if (hasPluginPackage) {
36276
37501
  const result = await installPluginPackage({
36277
37502
  agent,
36278
- includeHooks: plan.actions.includes("hooks")
37503
+ includeHooks: plan.includeHooks
36279
37504
  });
36280
37505
  v3.success(`${agent}: plugin package -> ${result.pluginPath}`);
36281
37506
  if (result.marketplacePath) {
@@ -36283,17 +37508,16 @@ async function installAgentSetup(agent, plan, global2) {
36283
37508
  }
36284
37509
  if (agent === "codex") {
36285
37510
  const install = tryInstallCodexPlugin();
36286
- if (install.ok) v3.success(install.message);
36287
- else v3.warn(install.message);
36288
37511
  if (install.ok) {
36289
- try {
36290
- const migration = await removeLegacyCodexMemorixMcpConfig();
36291
- if (migration.removed) {
36292
- v3.info(`codex: removed legacy source-path MCP config from ${migration.configPath}`);
36293
- }
36294
- } catch {
36295
- v3.warn("codex: plugin installed, but the legacy MCP config could not be checked");
36296
- }
37512
+ v3.success(install.message);
37513
+ const migration = await migrateLegacyCodexIntegration({ projectRoot: process.cwd() });
37514
+ if (migration.mcp === "removed") v3.info("codex: removed the legacy source-path MCP block; the enabled plugin now owns MCP.");
37515
+ if (migration.mcp === "preserved") v3.warn("codex: kept a customized legacy Memorix MCP block; remove it manually only after confirming plugin MCP works.");
37516
+ if (migration.projectHooks === "removed") v3.info("codex: removed a legacy project-local Memorix hooks.json; plugin hooks now own lifecycle capture.");
37517
+ if (migration.projectHooks === "preserved") v3.warn("codex: kept a project .codex/hooks.json because it contains non-Memorix commands.");
37518
+ if (migration.pluginFolder === "removed") v3.info("codex: removed the migrated legacy plugin folder under ~/.codex/plugins.");
37519
+ } else {
37520
+ v3.warn(install.message);
36297
37521
  }
36298
37522
  } else if (agent === "claude" && result.marketplaceRoot) {
36299
37523
  const install = tryInstallClaudePlugin(result.marketplaceRoot);
@@ -36371,6 +37595,8 @@ async function installAgentSetup(agent, plan, global2) {
36371
37595
  const result = await installMcpConfig({ agent, projectRoot: targetRoot, global: global2, mcp });
36372
37596
  v3.success(`${agent}: MCP config -> ${result.configPath}`);
36373
37597
  }
37598
+ } else if (agent === "codex" && !global2 && plan.mcp !== "none") {
37599
+ v3.info("codex: project-local .codex config is intentionally untouched. Run `memorix setup --agent codex --global` to install the user-level plugin.");
36374
37600
  }
36375
37601
  if (hasPluginPackage) {
36376
37602
  if (plan.actions.includes("project-guidance") && (agent === "claude" || agent === "codex")) {
@@ -36463,7 +37689,7 @@ var init_setup = __esm({
36463
37689
  ANTIGRAVITY_PLUGIN_AGENTS = /* @__PURE__ */ new Set(["antigravity"]);
36464
37690
  HERMES_PLUGIN_AGENTS = /* @__PURE__ */ new Set(["hermes"]);
36465
37691
  OMP_PACKAGE_AGENTS = /* @__PURE__ */ new Set(["omp"]);
36466
- PACKAGE_OWNED_INTEGRATION_AGENTS = /* @__PURE__ */ new Set(["antigravity", "openclaw", "hermes", "omp"]);
37692
+ PACKAGE_OWNED_INTEGRATION_AGENTS = /* @__PURE__ */ new Set(["codex", "antigravity", "openclaw", "hermes", "omp"]);
36467
37693
  SUPPORTED_SETUP_AGENTS = [
36468
37694
  "claude",
36469
37695
  "codex",
@@ -37022,6 +38248,7 @@ function receiptOmissionKind(raw) {
37022
38248
  if (raw.includes("state")) return "code-state";
37023
38249
  if (raw.includes("semantic")) return "semantic-code";
37024
38250
  if (raw.includes("start")) return "start-here";
38251
+ if (raw.includes("durable-memory")) return "durable-memory";
37025
38252
  if (raw.includes("memory")) return "memory";
37026
38253
  if (raw.includes("claim")) return "claim";
37027
38254
  if (raw.includes("knowledge-page")) return "knowledge-page";
@@ -37280,6 +38507,26 @@ function renderTaskWorksetPrompt(input) {
37280
38507
  });
37281
38508
  }
37282
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
+ }
37283
38530
  if (input.workflows.length > 0) {
37284
38531
  appendLine(lines, "", maxTokens, omitted, "workflow-heading");
37285
38532
  appendLine(lines, "Project workflow", maxTokens, omitted, "workflow-heading");
@@ -37349,6 +38596,32 @@ async function buildTaskWorkset(input) {
37349
38596
  evidenceRefs: evidenceByClaim.get(claim.id).map((item) => item.id),
37350
38597
  reason: selection.reasons[claim.id] ?? "source-qualified task match"
37351
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
+ }
37352
38625
  let workspace;
37353
38626
  let pages = [];
37354
38627
  let workflows = [];
@@ -37388,7 +38661,10 @@ async function buildTaskWorkset(input) {
37388
38661
  const evidenceIds = unique(selection.claims.flatMap((claim) => evidenceIdsForClaim(
37389
38662
  claim,
37390
38663
  evidenceByClaim.get(claim.id) ?? []
37391
- )));
38664
+ )).concat(
38665
+ durableMemory.map((memory) => "durable:" + memory.id),
38666
+ durableEvidence.map((evidence) => "durable-evidence:" + evidence.id)
38667
+ ));
37392
38668
  const verification = unique([
37393
38669
  ...workflows.flatMap((workflow) => workflow.verificationGates),
37394
38670
  ...input.verificationHints
@@ -37414,7 +38690,7 @@ async function buildTaskWorkset(input) {
37414
38690
  } : {}
37415
38691
  } : void 0;
37416
38692
  const base = {
37417
- version: "1.2",
38693
+ version: "1.3",
37418
38694
  task,
37419
38695
  lens: input.lens,
37420
38696
  currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
@@ -37427,6 +38703,7 @@ async function buildTaskWorkset(input) {
37427
38703
  hiddenCautionMemoryCount: input.hiddenCautionMemoryCount ?? 0,
37428
38704
  claims,
37429
38705
  pages,
38706
+ durableMemory,
37430
38707
  workflows,
37431
38708
  cautions: normalizedCautions,
37432
38709
  verification,
@@ -37443,7 +38720,7 @@ async function buildTaskWorkset(input) {
37443
38720
  budget: { maxTokens }
37444
38721
  });
37445
38722
  const receipt = {
37446
- version: "1.2.4",
38723
+ version: "1.3",
37447
38724
  target: input.deliveryTarget ?? "project-context",
37448
38725
  elapsedMs: Math.max(0, Date.now() - startedAt),
37449
38726
  budget: {
@@ -37478,6 +38755,7 @@ var init_workset = __esm({
37478
38755
  init_workspace();
37479
38756
  init_workflow_store();
37480
38757
  init_workflows();
38758
+ init_long_term();
37481
38759
  CONTINUATION_DETAIL_TOKEN_BUDGET = 20;
37482
38760
  }
37483
38761
  });
@@ -37490,7 +38768,7 @@ __export(current_facts_exports, {
37490
38768
  });
37491
38769
  import { execFileSync } from "child_process";
37492
38770
  import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
37493
- import path24 from "path";
38771
+ import path25 from "path";
37494
38772
  function readTextIfExists(filePath) {
37495
38773
  try {
37496
38774
  if (!existsSync13(filePath)) return null;
@@ -37500,7 +38778,7 @@ function readTextIfExists(filePath) {
37500
38778
  }
37501
38779
  }
37502
38780
  function readPackageVersion(rootPath) {
37503
- const text = readTextIfExists(path24.join(rootPath, "package.json"));
38781
+ const text = readTextIfExists(path25.join(rootPath, "package.json"));
37504
38782
  if (!text) return void 0;
37505
38783
  try {
37506
38784
  const parsed = JSON.parse(text);
@@ -37510,7 +38788,7 @@ function readPackageVersion(rootPath) {
37510
38788
  }
37511
38789
  }
37512
38790
  function readLatestChangelog(rootPath) {
37513
- const text = readTextIfExists(path24.join(rootPath, "CHANGELOG.md"));
38791
+ const text = readTextIfExists(path25.join(rootPath, "CHANGELOG.md"));
37514
38792
  if (!text) return void 0;
37515
38793
  const match = text.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
37516
38794
  if (!match) return void 0;
@@ -37580,7 +38858,7 @@ function detectStaleProgressNotes(input) {
37580
38858
  ];
37581
38859
  const notes = [];
37582
38860
  for (const relPath of candidates) {
37583
- const content = readTextIfExists(path24.join(input.rootPath, relPath));
38861
+ const content = readTextIfExists(path25.join(input.rootPath, relPath));
37584
38862
  if (!content) continue;
37585
38863
  const parsed = parseProgressNote(content);
37586
38864
  const olderThanChangelog = compareDateStrings(parsed.lastUpdated, input.latestChangelog?.date);
@@ -37831,9 +39109,9 @@ async function inspectExternalCodeGraph(input) {
37831
39109
  return { health, quality: providerQuality({ mode, health }) };
37832
39110
  }
37833
39111
  function safeRelativePath(projectRoot, value, exclude) {
37834
- const path37 = safeText(value, 1024);
37835
- if (!path37 || isAbsolute2(path37)) return void 0;
37836
- 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);
37837
39115
  const fromRoot = relative2(projectRoot, absolute);
37838
39116
  if (!fromRoot || fromRoot === ".." || fromRoot.startsWith("..\\") || fromRoot.startsWith("../") || isAbsolute2(fromRoot)) return void 0;
37839
39117
  const normalized = normalizeCodePath(fromRoot);
@@ -38115,15 +39393,15 @@ function countLanguages(files) {
38115
39393
  }
38116
39394
  return [...counts.entries()].map(([language, files2]) => ({ language, files: files2 })).sort((a3, b3) => a3.language.localeCompare(b3.language));
38117
39395
  }
38118
- function suggestedReadRank(path37) {
38119
- const normalized = path37.replace(/\\/g, "/");
39396
+ function suggestedReadRank(path38) {
39397
+ const normalized = path38.replace(/\\/g, "/");
38120
39398
  if (normalized.startsWith("src/")) return 0;
38121
39399
  if (normalized.startsWith("tests/") || normalized.startsWith("test/")) return 0;
38122
39400
  if (normalized.startsWith("packages/") && normalized.includes("/src/")) return 2;
38123
39401
  return 3;
38124
39402
  }
38125
39403
  function compactSuggestedReads(paths, limit = 8, exclude) {
38126
- 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);
38127
39405
  }
38128
39406
  function collectGraph(store2, projectId, observations2, exclude) {
38129
39407
  const files = store2.listFiles(projectId);
@@ -38163,14 +39441,14 @@ function collectGraph(store2, projectId, observations2, exclude) {
38163
39441
  }
38164
39442
  if (files.length === 0) {
38165
39443
  for (const observation of observations2) {
38166
- for (const path37 of observation.filesModified ?? []) {
38167
- if (!path37 || isCodeGraphExcludedPath(path37, exclude)) continue;
38168
- suggestedReads.push(path37);
39444
+ for (const path38 of observation.filesModified ?? []) {
39445
+ if (!path38 || isCodeGraphExcludedPath(path38, exclude)) continue;
39446
+ suggestedReads.push(path38);
38169
39447
  sources.push({
38170
39448
  observationId: observation.id,
38171
39449
  title: observation.title,
38172
39450
  type: observation.type,
38173
- path: path37,
39451
+ path: path38,
38174
39452
  status: "unbound",
38175
39453
  reason: "Recorded file hint; Code Memory refresh is pending."
38176
39454
  });
@@ -38254,7 +39532,7 @@ function formatProjectContextOverview(overview) {
38254
39532
  if (overview.suggestedReads.length === 0) {
38255
39533
  lines.push("- none yet");
38256
39534
  } else {
38257
- 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}`));
38258
39536
  }
38259
39537
  return lines.join("\n");
38260
39538
  }
@@ -38295,8 +39573,8 @@ __export(graph_store_exports, {
38295
39573
  initGraphStore: () => initGraphStore,
38296
39574
  resetGraphStore: () => resetGraphStore
38297
39575
  });
38298
- import path25 from "path";
38299
- import fs17 from "fs";
39576
+ import path26 from "path";
39577
+ import fs18 from "fs";
38300
39578
  function safeJsonParse3(val, fallback) {
38301
39579
  if (val == null || val === "") return fallback;
38302
39580
  try {
@@ -38386,8 +39664,8 @@ var init_graph_store = __esm({
38386
39664
  async migrateFromJsonlIfNeeded() {
38387
39665
  const count3 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM graph_entities`).get();
38388
39666
  if (count3.cnt > 0) return;
38389
- const jsonlPath = path25.join(this.dataDir, "graph.jsonl");
38390
- if (!fs17.existsSync(jsonlPath)) return;
39667
+ const jsonlPath = path26.join(this.dataDir, "graph.jsonl");
39668
+ if (!fs18.existsSync(jsonlPath)) return;
38391
39669
  try {
38392
39670
  const data = await loadGraphJsonl(this.dataDir);
38393
39671
  if (data.entities.length === 0 && data.relations.length === 0) return;
@@ -39129,8 +40407,8 @@ var compaction_checkpoint_store_exports = {};
39129
40407
  __export(compaction_checkpoint_store_exports, {
39130
40408
  CompactionCheckpointStore: () => CompactionCheckpointStore
39131
40409
  });
39132
- import { createHash as createHash12, randomUUID as randomUUID9 } from "crypto";
39133
- function optionalText5(value) {
40410
+ import { createHash as createHash12, randomUUID as randomUUID12 } from "crypto";
40411
+ function optionalText6(value) {
39134
40412
  return typeof value === "string" && value ? value : void 0;
39135
40413
  }
39136
40414
  function optionalNumber2(value) {
@@ -39184,15 +40462,15 @@ function rowToCheckpoint(row) {
39184
40462
  reason: row.reason,
39185
40463
  sourceEvent: row.source_event,
39186
40464
  sourceKey: row.source_key,
39187
- ...optionalText5(row.summary) ? { summary: row.summary } : {},
40465
+ ...optionalText6(row.summary) ? { summary: row.summary } : {},
39188
40466
  ...optionalNumber2(row.tokens_before) !== void 0 ? { tokensBefore: Number(row.tokens_before) } : {},
39189
- ...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 } : {},
39190
40468
  ...parseDetails(row.details_json) ? { details: parseDetails(row.details_json) } : {},
39191
40469
  transcriptAvailable: Boolean(row.transcript_available),
39192
40470
  status: row.status,
39193
40471
  preCapturedAt: row.pre_captured_at,
39194
- ...optionalText5(row.completed_at) ? { completedAt: row.completed_at } : {},
39195
- ...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 } : {},
39196
40474
  deliveryCount: Number(row.delivery_count ?? 0),
39197
40475
  createdAt: row.created_at,
39198
40476
  updatedAt: row.updated_at
@@ -39230,7 +40508,7 @@ var init_compaction_checkpoint_store = __esm({
39230
40508
  if (pending) return rowToCheckpoint(pending);
39231
40509
  const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
39232
40510
  const checkpoint = {
39233
- id: randomUUID9(),
40511
+ id: randomUUID12(),
39234
40512
  projectId: input.projectId,
39235
40513
  sessionId: input.sessionId,
39236
40514
  agent: input.agent,
@@ -39238,7 +40516,7 @@ var init_compaction_checkpoint_store = __esm({
39238
40516
  captureKind: "preflight",
39239
40517
  reason: safeReason(input.reason),
39240
40518
  sourceEvent: input.sourceEvent,
39241
- sourceKey: `pre:${randomUUID9()}`,
40519
+ sourceKey: `pre:${randomUUID12()}`,
39242
40520
  transcriptAvailable: Boolean(input.transcriptAvailable),
39243
40521
  status: "active",
39244
40522
  preCapturedAt: now3,
@@ -39304,7 +40582,7 @@ var init_compaction_checkpoint_store = __esm({
39304
40582
  return this.get(checkpoint2.id);
39305
40583
  }
39306
40584
  const checkpoint = {
39307
- id: randomUUID9(),
40585
+ id: randomUUID12(),
39308
40586
  projectId: input.projectId,
39309
40587
  sessionId: input.sessionId,
39310
40588
  agent: input.agent,
@@ -39439,7 +40717,7 @@ __export(auto_context_exports, {
39439
40717
  formatLegacyAutoProjectContextPrompt: () => formatLegacyAutoProjectContextPrompt
39440
40718
  });
39441
40719
  import { existsSync as existsSync15, statSync as statSync4 } from "fs";
39442
- import path26 from "path";
40720
+ import path27 from "path";
39443
40721
  function activeProjectObservations(observations2, projectId) {
39444
40722
  return observations2.filter((obs) => obs.projectId === projectId && (obs.status ?? "active") === "active");
39445
40723
  }
@@ -39674,6 +40952,7 @@ async function buildAutoProjectContext(input) {
39674
40952
  stale: overview.freshness.stale
39675
40953
  },
39676
40954
  runtimeCautions,
40955
+ ...input.reader ? { reader: input.reader } : {},
39677
40956
  ...input.deliveryTarget ? { deliveryTarget: input.deliveryTarget } : {}
39678
40957
  });
39679
40958
  return {
@@ -39718,7 +40997,7 @@ function dedupeSourcesByObservation(sources) {
39718
40997
  function existingLensCandidates(rootPath, lens) {
39719
40998
  const out = [];
39720
40999
  for (const candidate2 of lensPathCandidates(lens)) {
39721
- const absolute = path26.join(rootPath, candidate2);
41000
+ const absolute = path27.join(rootPath, candidate2);
39722
41001
  try {
39723
41002
  if (!existsSync15(absolute)) continue;
39724
41003
  const stat = statSync4(absolute);
@@ -39828,7 +41107,7 @@ function formatAutoProjectContextSummary(context) {
39828
41107
  "Start here"
39829
41108
  ].filter(Boolean);
39830
41109
  if (startHere.length > 0) {
39831
- startHere.forEach((path37, index) => lines.push(`${index + 1}. ${path37}`));
41110
+ startHere.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
39832
41111
  } else {
39833
41112
  lines.push("- no code-bound reads yet; inspect the task-relevant files directly");
39834
41113
  }
@@ -39837,6 +41116,14 @@ function formatAutoProjectContextSummary(context) {
39837
41116
  "Reliable memory",
39838
41117
  reliableSources.length > 0 ? `- ${reliableSources.length} current code-bound memory link(s)` : "- none yet"
39839
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
+ }
39840
41127
  const continuation = context.workset.continuation;
39841
41128
  if (continuation?.previousSession || continuation?.memories.length || continuation?.compactCheckpoint) {
39842
41129
  lines.push("", "Resume from prior work");
@@ -39886,7 +41173,7 @@ function formatLegacyAutoProjectContextPrompt(context) {
39886
41173
  if (startHere.length === 0) {
39887
41174
  lines.push("- no code-bound reads yet; inspect the task-relevant code directly");
39888
41175
  } else {
39889
- startHere.forEach((path37, index) => lines.push(`${index + 1}. ${path37}`));
41176
+ startHere.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
39890
41177
  }
39891
41178
  const { reliableSources, cautionSources, hiddenReliableCount, hiddenCautionCount } = lensSourceSets(context);
39892
41179
  lines.push("", "Reliable memory");
@@ -40354,6 +41641,7 @@ async function attachTaskWorkset(input) {
40354
41641
  stale: input.pack.warnings.filter((warning) => warning.status === "stale").length
40355
41642
  },
40356
41643
  runtimeCautions: input.runtimeCautions,
41644
+ ...input.reader ? { reader: input.reader } : {},
40357
41645
  deliveryTarget: "context-pack"
40358
41646
  });
40359
41647
  return { ...input.pack, workset };
@@ -40364,7 +41652,7 @@ function buildContextPackPrompt(pack) {
40364
41652
  const unboundMemories = pack.memories.filter((memory) => memory.status === "unbound");
40365
41653
  const lines = ["## Task", pack.task, "", "## Reliable Memories"];
40366
41654
  const visibleCodeFacts = pack.codeFacts.filter((fact) => !isCodeGraphExcludedPath(fact.path)).slice(0, 5);
40367
- const visibleSuggestedReads = pack.suggestedReads.filter((path37) => !isCodeGraphExcludedPath(path37)).slice(0, 5);
41655
+ const visibleSuggestedReads = pack.suggestedReads.filter((path38) => !isCodeGraphExcludedPath(path38)).slice(0, 5);
40368
41656
  if (reliableMemories.length === 0) lines.push("- none");
40369
41657
  for (const memory of reliableMemories) {
40370
41658
  lines.push(`- #${memory.id} ${memory.status}: [${memory.type}] ${memory.title} (${memory.reason})`);
@@ -40388,7 +41676,7 @@ function buildContextPackPrompt(pack) {
40388
41676
  }
40389
41677
  lines.push("", "## Suggested Next Reads");
40390
41678
  if (visibleSuggestedReads.length === 0) lines.push("- none");
40391
- visibleSuggestedReads.forEach((path37, index) => lines.push(`${index + 1}. ${path37}`));
41679
+ visibleSuggestedReads.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
40392
41680
  lines.push("", "## Suggested Verification");
40393
41681
  if (pack.suggestedVerification.length === 0) lines.push("- none");
40394
41682
  for (const command of pack.suggestedVerification) lines.push(`- ${command}`);
@@ -40601,7 +41889,8 @@ ${formatUsageHint()}`;
40601
41889
  } : {},
40602
41890
  ...external.outline ? { semanticCode: external.outline } : {},
40603
41891
  providerQuality: external.quality,
40604
- ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {}
41892
+ ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
41893
+ reader
40605
41894
  });
40606
41895
  emitResult({ project, pack, providerQuality: external.quality }, buildContextPackPrompt(pack), asJson);
40607
41896
  return;
@@ -42787,8 +44076,8 @@ var transfer_exports = {};
42787
44076
  __export(transfer_exports, {
42788
44077
  default: () => transfer_default
42789
44078
  });
42790
- import { promises as fs18 } from "fs";
42791
- import path27 from "path";
44079
+ import { promises as fs19 } from "fs";
44080
+ import path28 from "path";
42792
44081
  async function readStandardInput() {
42793
44082
  return new Promise((resolve6, reject) => {
42794
44083
  let content = "";
@@ -42809,13 +44098,13 @@ async function readImportPayload(args, projectRoot) {
42809
44098
  throw new Error("Choose exactly one import source: --data <json>, --file <path>, or --stdin.");
42810
44099
  }
42811
44100
  if (readFromStdin) return readStandardInput();
42812
- if (file) return fs18.readFile(path27.resolve(projectRoot, file), "utf8");
44101
+ if (file) return fs19.readFile(path28.resolve(projectRoot, file), "utf8");
42813
44102
  return data;
42814
44103
  }
42815
44104
  async function writeExportPayload(projectRoot, output, payload) {
42816
- const outputPath = path27.resolve(projectRoot, output);
42817
- await fs18.mkdir(path27.dirname(outputPath), { recursive: true });
42818
- 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");
42819
44108
  return outputPath;
42820
44109
  }
42821
44110
  var transfer_default;
@@ -44389,8 +45678,8 @@ var init_parseUtil = __esm({
44389
45678
  init_errors2();
44390
45679
  init_en();
44391
45680
  makeIssue = (params) => {
44392
- const { data, path: path37, errorMaps, issueData } = params;
44393
- const fullPath = [...path37, ...issueData.path || []];
45681
+ const { data, path: path38, errorMaps, issueData } = params;
45682
+ const fullPath = [...path38, ...issueData.path || []];
44394
45683
  const fullIssue = {
44395
45684
  ...issueData,
44396
45685
  path: fullPath
@@ -44427,15 +45716,15 @@ var init_parseUtil = __esm({
44427
45716
  this.value = "aborted";
44428
45717
  }
44429
45718
  static mergeArray(status, results) {
44430
- const arrayValue2 = [];
45719
+ const arrayValue3 = [];
44431
45720
  for (const s2 of results) {
44432
45721
  if (s2.status === "aborted")
44433
45722
  return INVALID;
44434
45723
  if (s2.status === "dirty")
44435
45724
  status.dirty();
44436
- arrayValue2.push(s2.value);
45725
+ arrayValue3.push(s2.value);
44437
45726
  }
44438
- return { status: status.value, value: arrayValue2 };
45727
+ return { status: status.value, value: arrayValue3 };
44439
45728
  }
44440
45729
  static async mergeObjectAsync(status, pairs) {
44441
45730
  const syncPairs = [];
@@ -44704,11 +45993,11 @@ var init_types3 = __esm({
44704
45993
  init_parseUtil();
44705
45994
  init_util2();
44706
45995
  ParseInputLazyPath = class {
44707
- constructor(parent, value, path37, key) {
45996
+ constructor(parent, value, path38, key) {
44708
45997
  this._cachedPath = [];
44709
45998
  this.parent = parent;
44710
45999
  this.data = value;
44711
- this._path = path37;
46000
+ this._path = path38;
44712
46001
  this._key = key;
44713
46002
  }
44714
46003
  get path() {
@@ -48461,7 +49750,7 @@ function collectCodeMemory(opts) {
48461
49750
  if (status.indexedAt) lines.push(`Last scan: ${status.indexedAt}`);
48462
49751
  if (suggestedReads.length > 0) {
48463
49752
  lines.push("Suggested reads:");
48464
- suggestedReads.forEach((path37, index) => lines.push(`${index + 1}. ${path37}`));
49753
+ suggestedReads.forEach((path38, index) => lines.push(`${index + 1}. ${path38}`));
48465
49754
  }
48466
49755
  return lines.join("\n");
48467
49756
  } catch {
@@ -48486,7 +49775,7 @@ __export(planner_exports, {
48486
49775
  materializeTaskGraph: () => materializeTaskGraph,
48487
49776
  seedAutonomousPipeline: () => seedAutonomousPipeline
48488
49777
  });
48489
- import { randomUUID as randomUUID10 } from "crypto";
49778
+ import { randomUUID as randomUUID13 } from "crypto";
48490
49779
  function isPlannerTask(metadata) {
48491
49780
  if (!metadata) return null;
48492
49781
  try {
@@ -48544,7 +49833,7 @@ function seedAutonomousPipeline(teamStore, projectId, config2, opts) {
48544
49833
  const maxIterations = config2.maxIterations ?? 3;
48545
49834
  const taskBudget = config2.taskBudget ?? 15;
48546
49835
  const structuredPlan = opts?.structuredPlan ?? true;
48547
- const pipelineId = randomUUID10();
49836
+ const pipelineId = randomUUID13();
48548
49837
  const meta = {
48549
49838
  plannerType: "plan",
48550
49839
  pipelineId,
@@ -49465,7 +50754,7 @@ __export(receipt_service_exports, {
49465
50754
  });
49466
50755
  import { createHash as createHash13 } from "crypto";
49467
50756
  import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
49468
- import path28 from "path";
50757
+ import path29 from "path";
49469
50758
  function sha256(value) {
49470
50759
  return `sha256:${createHash13("sha256").update(value).digest("hex")}`;
49471
50760
  }
@@ -49494,7 +50783,7 @@ function safeJsonArray(value) {
49494
50783
  }
49495
50784
  }
49496
50785
  async function loadReceiptObservations(dataDir, projectId) {
49497
- const dbPath = path28.join(dataDir, "memorix.db");
50786
+ const dbPath = path29.join(dataDir, "memorix.db");
49498
50787
  if (existsSync18(dbPath)) {
49499
50788
  try {
49500
50789
  const DB = loadBetterSqlite3();
@@ -49511,7 +50800,7 @@ async function loadReceiptObservations(dataDir, projectId) {
49511
50800
  } catch {
49512
50801
  }
49513
50802
  }
49514
- const jsonPath = path28.join(dataDir, "observations.json");
50803
+ const jsonPath = path29.join(dataDir, "observations.json");
49515
50804
  if (!existsSync18(jsonPath)) return [];
49516
50805
  try {
49517
50806
  const parsed = JSON.parse(readFileSync12(jsonPath, "utf-8"));
@@ -49932,10 +51221,10 @@ function assignProp(target, prop, value) {
49932
51221
  configurable: true
49933
51222
  });
49934
51223
  }
49935
- function getElementAtPath(obj, path37) {
49936
- if (!path37)
51224
+ function getElementAtPath(obj, path38) {
51225
+ if (!path38)
49937
51226
  return obj;
49938
- return path37.reduce((acc, key) => acc?.[key], obj);
51227
+ return path38.reduce((acc, key) => acc?.[key], obj);
49939
51228
  }
49940
51229
  function promiseAllObject(promisesObj) {
49941
51230
  const keys = Object.keys(promisesObj);
@@ -50184,11 +51473,11 @@ function aborted(x3, startIndex = 0) {
50184
51473
  }
50185
51474
  return false;
50186
51475
  }
50187
- function prefixIssues(path37, issues) {
51476
+ function prefixIssues(path38, issues) {
50188
51477
  return issues.map((iss) => {
50189
51478
  var _a;
50190
51479
  (_a = iss).path ?? (_a.path = []);
50191
- iss.path.unshift(path37);
51480
+ iss.path.unshift(path38);
50192
51481
  return iss;
50193
51482
  });
50194
51483
  }
@@ -62494,8 +63783,8 @@ var require_utils2 = __commonJS({
62494
63783
  }
62495
63784
  return ind;
62496
63785
  }
62497
- function removeDotSegments(path37) {
62498
- let input = path37;
63786
+ function removeDotSegments(path38) {
63787
+ let input = path38;
62499
63788
  const output = [];
62500
63789
  let nextSlash = -1;
62501
63790
  let len = 0;
@@ -62748,8 +64037,8 @@ var require_schemes = __commonJS({
62748
64037
  wsComponent.secure = void 0;
62749
64038
  }
62750
64039
  if (wsComponent.resourceName) {
62751
- const [path37, query] = wsComponent.resourceName.split("?");
62752
- wsComponent.path = path37 && path37 !== "/" ? path37 : void 0;
64040
+ const [path38, query] = wsComponent.resourceName.split("?");
64041
+ wsComponent.path = path38 && path38 !== "/" ? path38 : void 0;
62753
64042
  wsComponent.query = query;
62754
64043
  wsComponent.resourceName = void 0;
62755
64044
  }
@@ -66188,12 +67477,12 @@ var require_dist = __commonJS({
66188
67477
  throw new Error(`Unknown format "${name}"`);
66189
67478
  return f4;
66190
67479
  };
66191
- function addFormats(ajv, list, fs27, exportName) {
67480
+ function addFormats(ajv, list, fs28, exportName) {
66192
67481
  var _a;
66193
67482
  var _b;
66194
67483
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
66195
67484
  for (const f4 of list)
66196
- ajv.addFormat(f4, fs27[f4]);
67485
+ ajv.addFormat(f4, fs28[f4]);
66197
67486
  }
66198
67487
  module2.exports = exports2 = formatsPlugin;
66199
67488
  Object.defineProperty(exports2, "__esModule", { value: true });
@@ -68669,8 +69958,8 @@ var syncer_exports = {};
68669
69958
  __export(syncer_exports, {
68670
69959
  RulesSyncer: () => RulesSyncer
68671
69960
  });
68672
- import { promises as fs19 } from "fs";
68673
- import path29 from "path";
69961
+ import { promises as fs20 } from "fs";
69962
+ import path30 from "path";
68674
69963
  var RulesSyncer;
68675
69964
  var init_syncer = __esm({
68676
69965
  "src/rules/syncer.ts"() {
@@ -68715,8 +70004,8 @@ var init_syncer = __esm({
68715
70004
  const found = await this.findFiles(scanPath);
68716
70005
  for (const filePath of found) {
68717
70006
  try {
68718
- const content = await fs19.readFile(filePath, "utf-8");
68719
- 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, "/");
68720
70009
  const parsed = entry.adapter.parse(relativePath, content);
68721
70010
  rules.push(...parsed);
68722
70011
  } catch {
@@ -68784,7 +70073,7 @@ var init_syncer = __esm({
68784
70073
  const entries = [];
68785
70074
  for (const adapter of this.adapters.values()) {
68786
70075
  const absolutePaths = adapter.filePatterns.map(
68787
- (p2) => path29.join(this.projectRoot, p2)
70076
+ (p2) => path30.join(this.projectRoot, p2)
68788
70077
  );
68789
70078
  entries.push({ adapter, paths: absolutePaths });
68790
70079
  }
@@ -68792,13 +70081,13 @@ var init_syncer = __esm({
68792
70081
  }
68793
70082
  /** Find files matching a glob-like path (simple implementation) */
68794
70083
  async findFiles(pattern) {
68795
- const dir = path29.dirname(pattern);
68796
- const fileGlob = path29.basename(pattern);
70084
+ const dir = path30.dirname(pattern);
70085
+ const fileGlob = path30.basename(pattern);
68797
70086
  try {
68798
- const stat = await fs19.stat(dir);
70087
+ const stat = await fs20.stat(dir);
68799
70088
  if (!stat.isDirectory()) {
68800
70089
  try {
68801
- await fs19.access(pattern);
70090
+ await fs20.access(pattern);
68802
70091
  return [pattern];
68803
70092
  } catch {
68804
70093
  return [];
@@ -68806,7 +70095,7 @@ var init_syncer = __esm({
68806
70095
  }
68807
70096
  } catch {
68808
70097
  try {
68809
- await fs19.access(pattern);
70098
+ await fs20.access(pattern);
68810
70099
  return [pattern];
68811
70100
  } catch {
68812
70101
  return [];
@@ -68814,16 +70103,16 @@ var init_syncer = __esm({
68814
70103
  }
68815
70104
  if (fileGlob.includes("*")) {
68816
70105
  try {
68817
- const files = await fs19.readdir(dir);
70106
+ const files = await fs20.readdir(dir);
68818
70107
  const ext = fileGlob.replace("*", "");
68819
- 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));
68820
70109
  } catch {
68821
70110
  return [];
68822
70111
  }
68823
70112
  }
68824
70113
  try {
68825
- await fs19.access(path29.join(dir, fileGlob));
68826
- return [path29.join(dir, fileGlob)];
70114
+ await fs20.access(path30.join(dir, fileGlob));
70115
+ return [path30.join(dir, fileGlob)];
68827
70116
  } catch {
68828
70117
  return [];
68829
70118
  }
@@ -69058,10 +70347,10 @@ var init_engine3 = __esm({
69058
70347
  pathsToCheck.push(join25(homedir29(), ".gemini", "antigravity", "mcp_config.json"));
69059
70348
  }
69060
70349
  const merged = /* @__PURE__ */ new Map();
69061
- for (const path37 of pathsToCheck) {
69062
- if (existsSync20(path37)) {
70350
+ for (const path38 of pathsToCheck) {
70351
+ if (existsSync20(path38)) {
69063
70352
  try {
69064
- const content = readFileSync13(path37, "utf-8");
70353
+ const content = readFileSync13(path38, "utf-8");
69065
70354
  const servers = adapter.parse(content);
69066
70355
  for (const s2 of servers) {
69067
70356
  if (!merged.has(s2.name)) merged.set(s2.name, s2);
@@ -70038,8 +71327,8 @@ __export(server_exports, {
70038
71327
  startDashboard: () => startDashboard
70039
71328
  });
70040
71329
  import { createServer } from "http";
70041
- import { promises as fs20 } from "fs";
70042
- import path30 from "path";
71330
+ import { promises as fs21 } from "fs";
71331
+ import path31 from "path";
70043
71332
  import { exec } from "child_process";
70044
71333
  function sendJson(res, data, status = 200) {
70045
71334
  res.writeHead(status, {
@@ -70517,7 +71806,7 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
70517
71806
  const aliasModule = await Promise.resolve().then(() => (init_aliases(), aliases_exports));
70518
71807
  canonicalId = await aliasModule.getCanonicalId(effectiveProjectId);
70519
71808
  const { promises: fsP } = await import("fs");
70520
- const registryPath = path30.join(baseDir, ".project-aliases.json");
71809
+ const registryPath = path31.join(baseDir, ".project-aliases.json");
70521
71810
  const raw = await fsP.readFile(registryPath, "utf-8");
70522
71811
  const registry2 = JSON.parse(raw);
70523
71812
  aliasGroups = registry2.groups || [];
@@ -70632,14 +71921,14 @@ async function serveStatic(req, res, staticDir) {
70632
71921
  if (urlPath === "/" || !urlPath.includes(".")) {
70633
71922
  urlPath = "/index.html";
70634
71923
  }
70635
- const filePath = path30.join(staticDir, urlPath);
71924
+ const filePath = path31.join(staticDir, urlPath);
70636
71925
  if (!filePath.startsWith(staticDir)) {
70637
71926
  sendError(res, "Forbidden", 403);
70638
71927
  return;
70639
71928
  }
70640
71929
  try {
70641
- const data = await fs20.readFile(filePath);
70642
- const ext = path30.extname(filePath);
71930
+ const data = await fs21.readFile(filePath);
71931
+ const ext = path31.extname(filePath);
70643
71932
  res.writeHead(200, {
70644
71933
  "Content-Type": MIME_TYPES[ext] || "application/octet-stream",
70645
71934
  "Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
@@ -70649,7 +71938,7 @@ async function serveStatic(req, res, staticDir) {
70649
71938
  res.end(data);
70650
71939
  } catch {
70651
71940
  try {
70652
- const indexData = await fs20.readFile(path30.join(staticDir, "index.html"));
71941
+ const indexData = await fs21.readFile(path31.join(staticDir, "index.html"));
70653
71942
  res.writeHead(200, {
70654
71943
  "Content-Type": "text/html; charset=utf-8",
70655
71944
  "Cache-Control": "no-store, no-cache, must-revalidate, max-age=0",
@@ -71090,9 +72379,9 @@ __export(hooks_path_exports, {
71090
72379
  resolveHooksDir: () => resolveHooksDir
71091
72380
  });
71092
72381
  import { existsSync as existsSync22, readFileSync as readFileSync15, statSync as statSync5, mkdirSync as mkdirSync6 } from "fs";
71093
- import path31 from "path";
72382
+ import path32 from "path";
71094
72383
  function resolveGitDir(projectRoot) {
71095
- const dotGit = path31.join(projectRoot, ".git");
72384
+ const dotGit = path32.join(projectRoot, ".git");
71096
72385
  if (!existsSync22(dotGit)) return null;
71097
72386
  const stat = statSync5(dotGit);
71098
72387
  if (stat.isDirectory()) {
@@ -71104,7 +72393,7 @@ function resolveGitDir(projectRoot) {
71104
72393
  const match = content.match(/^gitdir:\s*(.+)$/);
71105
72394
  if (match) {
71106
72395
  const gitdir = match[1].trim();
71107
- const resolved = path31.isAbsolute(gitdir) ? gitdir : path31.resolve(projectRoot, gitdir);
72396
+ const resolved = path32.isAbsolute(gitdir) ? gitdir : path32.resolve(projectRoot, gitdir);
71108
72397
  if (existsSync22(resolved)) {
71109
72398
  return resolved;
71110
72399
  }
@@ -71117,10 +72406,10 @@ function resolveGitDir(projectRoot) {
71117
72406
  function resolveHooksDir(projectRoot) {
71118
72407
  const gitDir = resolveGitDir(projectRoot);
71119
72408
  if (!gitDir) return null;
71120
- const hooksDir = path31.join(gitDir, "hooks");
72409
+ const hooksDir = path32.join(gitDir, "hooks");
71121
72410
  return {
71122
72411
  hooksDir,
71123
- hookPath: path31.join(hooksDir, "post-commit")
72412
+ hookPath: path32.join(hooksDir, "post-commit")
71124
72413
  };
71125
72414
  }
71126
72415
  function ensureHooksDir(projectRoot) {
@@ -71498,7 +72787,7 @@ The path should point to a directory containing a .git folder.`
71498
72787
  };
71499
72788
  const server = existingServer ?? new McpServer({
71500
72789
  name: "memorix",
71501
- version: true ? "1.2.9" : "1.0.1"
72790
+ version: true ? "1.3.0" : "1.0.1"
71502
72791
  });
71503
72792
  const originalRegisterTool = server.registerTool.bind(server);
71504
72793
  server.registerTool = ((name, ...args) => {
@@ -71578,7 +72867,7 @@ The path should point to a directory containing a .git folder.`
71578
72867
  "memorix_store",
71579
72868
  {
71580
72869
  title: "Store Memory",
71581
- 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.",
71582
72871
  inputSchema: {
71583
72872
  entityName: external_exports.string().describe('The entity this observation belongs to (e.g., "auth-module", "port-config")'),
71584
72873
  type: external_exports.enum(OBSERVATION_TYPES2).describe("Observation type for classification"),
@@ -71600,30 +72889,43 @@ The path should point to a directory containing a .git folder.`
71600
72889
  visibility: external_exports.enum(["personal", "project", "team"]).optional().describe(
71601
72890
  "Retrieval scope. Project is the normal shared default; personal/team require memorix_session_start with joinTeam=true."
71602
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."),
71603
72898
  overrideReadOnly: external_exports.boolean().optional().describe(
71604
72899
  "Use only when the user explicitly asks to save memory during a read-only or no-modification task."
71605
72900
  )
71606
72901
  }
71607
72902
  },
71608
- 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 }) => {
71609
72904
  const unresolved = requireResolvedProject("store memory in the current project");
71610
72905
  if (unresolved) return unresolved;
71611
72906
  const readOnlyBoundary = blockReadOnlyAutopilotWrite(overrideReadOnly);
71612
72907
  if (readOnlyBoundary) return readOnlyBoundary;
71613
- const requestedVisibility = visibility ?? "project";
72908
+ const requestedVisibility = longTerm?.scope === "user" ? "personal" : longTerm?.scope === "team" ? "team" : visibility;
72909
+ const effectiveVisibility = requestedVisibility ?? "project";
71614
72910
  const reader = getObservationReader();
71615
- if (requestedVisibility !== "project" && !currentAgentId) {
72911
+ if (effectiveVisibility !== "project" && !currentAgentId) {
71616
72912
  return {
71617
72913
  content: [{ type: "text", text: "Personal or team memory requires memorix_session_start with joinTeam=true so Memorix can bind an owner." }],
71618
72914
  isError: true
71619
72915
  };
71620
72916
  }
71621
- if (requestedVisibility === "team" && !reader.isTeamMember) {
72917
+ if (effectiveVisibility === "team" && !reader.isTeamMember) {
71622
72918
  return {
71623
72919
  content: [{ type: "text", text: "Team memory requires an active coordination membership in the current project." }],
71624
72920
  isError: true
71625
72921
  };
71626
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
+ }
71627
72929
  try {
71628
72930
  return await withFreshIndex(async () => {
71629
72931
  let entityName = rawEntityName;
@@ -71645,7 +72947,7 @@ The path should point to a directory containing a .git folder.`
71645
72947
  const useFormation = formationMode === "active";
71646
72948
  let formationResult = null;
71647
72949
  let formationNote = "";
71648
- if (useFormation && !topicKey && !progress) {
72950
+ if (useFormation && !topicKey && !progress && !longTerm) {
71649
72951
  let currentFormationStage = "setup";
71650
72952
  const completedFormationStages = {};
71651
72953
  const formationStartTime = Date.now();
@@ -71796,7 +73098,7 @@ ${modeIcon} Formation[active]: ${formationResult.evaluation.category} (${formati
71796
73098
  }
71797
73099
  let compactAction = "";
71798
73100
  let compactMerged = false;
71799
- if (!useFormation && !topicKey && !progress) {
73101
+ if (!useFormation && !topicKey && !progress && !longTerm) {
71800
73102
  try {
71801
73103
  const searchResult = await compactSearch({
71802
73104
  query: `${title} ${narrative.substring(0, 200)}`,
@@ -71953,9 +73255,33 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
71953
73255
  sourceDetail: "explicit",
71954
73256
  valueCategory: formationResult?.evaluation.category,
71955
73257
  createdByAgentId: currentAgentId,
71956
- visibility,
73258
+ visibility: requestedVisibility,
71957
73259
  visibilityReader: reader
71958
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
+ }
71959
73285
  await graphManager.addObservations([
71960
73286
  { entityName, contents: [`[#${obs.id}] ${title}`] }
71961
73287
  ]);
@@ -71972,7 +73298,7 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
71972
73298
  const enrichment = enrichmentParts.length > 0 ? `
71973
73299
  Auto-enriched: ${enrichmentParts.join(", ")}` : "";
71974
73300
  const action = upserted ? "[UPDATED] Updated" : "[OK] Stored";
71975
- if (!useFormation && !topicKey && !progress) {
73301
+ if (!useFormation && !topicKey && !progress && !longTerm) {
71976
73302
  const shadowFormation = async () => {
71977
73303
  let oldCompactDecision = null;
71978
73304
  try {
@@ -72062,7 +73388,7 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
72062
73388
  {
72063
73389
  type: "text",
72064
73390
  text: `${action} observation #${obs.id} "${title}" (~${obs.tokens} tokens)
72065
- 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}`
72066
73392
  }
72067
73393
  ]
72068
73394
  };
@@ -72435,7 +73761,8 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
72435
73761
  } : {},
72436
73762
  ...external.outline ? { semanticCode: external.outline } : {},
72437
73763
  providerQuality: external.quality,
72438
- ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {}
73764
+ ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
73765
+ reader: getObservationReader()
72439
73766
  });
72440
73767
  const text = buildContextPackPrompt2(pack);
72441
73768
  return {
@@ -73109,7 +74436,7 @@ ${actions.join("\n")}`
73109
74436
  "memorix_detail",
73110
74437
  {
73111
74438
  title: "Memory Details",
73112
- 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.',
73113
74440
  inputSchema: {
73114
74441
  ids: external_exports.array(external_exports.number()).optional().describe("Observation IDs to fetch (legacy, from memorix_search results)"),
73115
74442
  refs: external_exports.array(
@@ -73118,7 +74445,7 @@ ${actions.join("\n")}`
73118
74445
  projectId: external_exports.string().optional().describe("Project ID for global-search disambiguation")
73119
74446
  })
73120
74447
  ).optional().describe("Explicit observation refs. Prefer this for global search results."),
73121
- 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"'),
73122
74449
  purpose: external_exports.string().optional().describe(
73123
74450
  "Why this must expand beyond the latest Autopilot brief. Name the missing fact or the user's explicit request."
73124
74451
  ),
@@ -73131,14 +74458,19 @@ ${actions.join("\n")}`
73131
74458
  const safeIds = coerceNumberArray(ids);
73132
74459
  const safeRefs = coerceObservationRefs(refs);
73133
74460
  const safeTypedRefs = coerceStringArray(typedRefs);
73134
- 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}`));
73135
74467
  if (!hasCrossProjectRef) {
73136
74468
  const boundary = requireExplicitAutopilotExpansion("memorix_detail", purpose);
73137
74469
  if (boundary) return boundary;
73138
74470
  const requestedObservationIds = [
73139
74471
  ...safeIds,
73140
74472
  ...safeRefs.map((ref) => ref.id),
73141
- ...safeTypedRefs.flatMap((ref) => {
74473
+ ...observationTypedRefs.flatMap((ref) => {
73142
74474
  const match = /^obs:(\d+)(?:@.+)?$/i.exec(ref.trim());
73143
74475
  return match ? [Number(match[1])] : [];
73144
74476
  })
@@ -73146,15 +74478,36 @@ ${actions.join("\n")}`
73146
74478
  const duplicate = blockCoveredAutopilotEvidence("memorix_detail", requestedObservationIds, force);
73147
74479
  if (duplicate) return duplicate;
73148
74480
  }
73149
- let result;
74481
+ const formatted = [];
73150
74482
  try {
73151
- const reader = getObservationReader(hasCrossProjectRef ? "global" : "project");
73152
- if (safeTypedRefs.length > 0) {
73153
- result = await compactDetail(safeTypedRefs, { reader });
73154
- } else if (safeRefs.length > 0) {
73155
- result = await compactDetail(safeRefs, { reader });
73156
- } else {
73157
- 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
+ );
73158
74511
  }
73159
74512
  } catch (err) {
73160
74513
  return { content: [{ type: "text", text: err instanceof Error ? err.message : String(err) }], isError: true };
@@ -73163,7 +74516,7 @@ ${actions.join("\n")}`
73163
74516
  content: [
73164
74517
  {
73165
74518
  type: "text",
73166
- 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(", ")}`
73167
74520
  }
73168
74521
  ]
73169
74522
  };
@@ -73883,9 +75236,9 @@ ${skill2.content}` }]
73883
75236
  lines.push(`- **Description**: ${sk.description}`);
73884
75237
  lines.push(`- **Observations**: ${sk.content.split("\n").length} lines of knowledge`);
73885
75238
  if (write && target) {
73886
- const path37 = engine.writeSkill(sk, target);
73887
- if (path37) {
73888
- lines.push(`- [OK] **Written**: \`${path37}\``);
75239
+ const path38 = engine.writeSkill(sk, target);
75240
+ if (path38) {
75241
+ lines.push(`- [OK] **Written**: \`${path38}\``);
73889
75242
  } else {
73890
75243
  lines.push(`- [ERROR] Failed to write`);
73891
75244
  }
@@ -75717,8 +77070,8 @@ var init_serve = __esm({
75717
77070
  safeCwd = homedir34();
75718
77071
  }
75719
77072
  const { existsSync: existsSync31, readFileSync: readFileSync23 } = await import("fs");
75720
- const path37 = await import("path");
75721
- 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");
75722
77075
  let lastKnownProjectRoot;
75723
77076
  if (existsSync31(lastRootFile)) {
75724
77077
  try {
@@ -75753,9 +77106,9 @@ var init_serve = __esm({
75753
77106
  if (detected) {
75754
77107
  try {
75755
77108
  const { writeFileSync: writeFileSync11, mkdirSync: mkdirSync11 } = await import("fs");
75756
- const memorixDir = path37.join(homedir34(), ".memorix");
77109
+ const memorixDir = path38.join(homedir34(), ".memorix");
75757
77110
  mkdirSync11(memorixDir, { recursive: true });
75758
- writeFileSync11(path37.join(memorixDir, "last-project-root"), detected.rootPath, "utf-8");
77111
+ writeFileSync11(path38.join(memorixDir, "last-project-root"), detected.rootPath, "utf-8");
75759
77112
  } catch {
75760
77113
  }
75761
77114
  }
@@ -77296,7 +78649,7 @@ var init_serve_http = __esm({
77296
78649
  },
77297
78650
  run: async ({ args }) => {
77298
78651
  const { createServer: createServer2 } = await import("http");
77299
- const { randomUUID: randomUUID11 } = await import("crypto");
78652
+ const { randomUUID: randomUUID14 } = await import("crypto");
77300
78653
  const { StreamableHTTPServerTransport: StreamableHTTPServerTransport2 } = await Promise.resolve().then(() => (init_streamableHttp(), streamableHttp_exports));
77301
78654
  const { isInitializeRequest: isInitializeRequest2 } = await Promise.resolve().then(() => (init_types4(), types_exports));
77302
78655
  const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server4(), server_exports2));
@@ -77480,7 +78833,7 @@ var init_serve_http = __esm({
77480
78833
  if (!sessionId && isInitializeRequest2(body)) {
77481
78834
  let createdState = null;
77482
78835
  const transport = new StreamableHTTPServerTransport2({
77483
- sessionIdGenerator: () => randomUUID11(),
78836
+ sessionIdGenerator: () => randomUUID14(),
77484
78837
  enableJsonResponse: true,
77485
78838
  onsessioninitialized: (sid) => {
77486
78839
  if (createdState) sessions.set(sid, createdState);
@@ -78847,8 +80200,8 @@ var init_sync = __esm({
78847
80200
  }
78848
80201
  const { detectProject: detectProject2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
78849
80202
  const { RulesSyncer: RulesSyncer2 } = await Promise.resolve().then(() => (init_syncer(), syncer_exports));
78850
- const { promises: fs27 } = await import("fs");
78851
- const path37 = await import("path");
80203
+ const { promises: fs28 } = await import("fs");
80204
+ const path38 = await import("path");
78852
80205
  we("memorix sync");
78853
80206
  const project = detectProject2();
78854
80207
  if (!project) {
@@ -78920,9 +80273,9 @@ var init_sync = __esm({
78920
80273
  process.exit(0);
78921
80274
  }
78922
80275
  for (const file of files) {
78923
- const fullPath = path37.join(project.rootPath, file.filePath);
78924
- await fs27.mkdir(path37.dirname(fullPath), { recursive: true });
78925
- 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");
78926
80279
  v3.success(`Written: ${file.filePath}`);
78927
80280
  }
78928
80281
  fe2(`Synced ${files.length} rule(s) to ${target} format`);
@@ -80809,8 +82162,8 @@ var hooks_preview_exports = {};
80809
82162
  __export(hooks_preview_exports, {
80810
82163
  default: () => hooks_preview_default
80811
82164
  });
80812
- import * as fs21 from "fs/promises";
80813
- import * as path32 from "path";
82165
+ import * as fs22 from "fs/promises";
82166
+ import * as path33 from "path";
80814
82167
  function estimateFileSize(agent, configPath) {
80815
82168
  const sizes = {
80816
82169
  claude: "~2KB",
@@ -80830,30 +82183,30 @@ function getRulesPath(agent, cwd, global2) {
80830
82183
  if (global2) {
80831
82184
  switch (agent) {
80832
82185
  case "cursor":
80833
- return path32.join(home, ".cursor", "rules", "memorix.mdc");
82186
+ return path33.join(home, ".cursor", "rules", "memorix.mdc");
80834
82187
  case "codex":
80835
- return path32.join(home, ".codex", "AGENTS.md");
82188
+ return path33.join(home, ".codex", "AGENTS.md");
80836
82189
  case "opencode":
80837
- return path32.join(home, ".config", "opencode", "AGENTS.md");
82190
+ return path33.join(home, ".config", "opencode", "AGENTS.md");
80838
82191
  case "antigravity":
80839
- return path32.join(home, ".gemini", "GEMINI.md");
82192
+ return path33.join(home, ".gemini", "GEMINI.md");
80840
82193
  case "trae":
80841
- return path32.join(home, ".trae", "rules", "project_rules.md");
82194
+ return path33.join(home, ".trae", "rules", "project_rules.md");
80842
82195
  default:
80843
82196
  return "";
80844
82197
  }
80845
82198
  } else {
80846
82199
  switch (agent) {
80847
82200
  case "cursor":
80848
- return path32.join(cwd, ".cursor", "rules", "memorix.mdc");
82201
+ return path33.join(cwd, ".cursor", "rules", "memorix.mdc");
80849
82202
  case "codex":
80850
- return path32.join(cwd, "AGENTS.md");
82203
+ return path33.join(cwd, "AGENTS.md");
80851
82204
  case "opencode":
80852
- return path32.join(cwd, "AGENTS.md");
82205
+ return path33.join(cwd, "AGENTS.md");
80853
82206
  case "antigravity":
80854
- return path32.join(cwd, "GEMINI.md");
82207
+ return path33.join(cwd, "GEMINI.md");
80855
82208
  case "trae":
80856
- return path32.join(cwd, ".trae", "rules", "project_rules.md");
82209
+ return path33.join(cwd, ".trae", "rules", "project_rules.md");
80857
82210
  default:
80858
82211
  return "";
80859
82212
  }
@@ -80910,7 +82263,7 @@ var init_hooks_preview = __esm({
80910
82263
  const configPath = global2 ? getGlobalConfigPath2(agent) : getProjectConfigPath2(agent, cwd);
80911
82264
  let action;
80912
82265
  try {
80913
- await fs21.access(configPath);
82266
+ await fs22.access(configPath);
80914
82267
  action = "modify";
80915
82268
  } catch {
80916
82269
  action = "create";
@@ -80925,7 +82278,7 @@ var init_hooks_preview = __esm({
80925
82278
  if (["cursor", "codex", "opencode", "antigravity", "trae"].includes(agent)) {
80926
82279
  const rulesPath = getRulesPath(agent, cwd, global2);
80927
82280
  try {
80928
- await fs21.access(rulesPath);
82281
+ await fs22.access(rulesPath);
80929
82282
  previewItems.push({
80930
82283
  agent,
80931
82284
  path: rulesPath,
@@ -80942,10 +82295,10 @@ var init_hooks_preview = __esm({
80942
82295
  }
80943
82296
  }
80944
82297
  if (agent === "kiro") {
80945
- const hooksDir = path32.dirname(configPath);
82298
+ const hooksDir = path33.dirname(configPath);
80946
82299
  previewItems.push({
80947
82300
  agent,
80948
- path: path32.join(hooksDir, "*.kiro.hook"),
82301
+ path: path33.join(hooksDir, "*.kiro.hook"),
80949
82302
  action: "create",
80950
82303
  size: "~500B each"
80951
82304
  });
@@ -81716,9 +83069,9 @@ __export(ingest_image_exports, {
81716
83069
  default: () => ingest_image_default
81717
83070
  });
81718
83071
  import { readFileSync as readFileSync16 } from "fs";
81719
- import path33 from "path";
83072
+ import path34 from "path";
81720
83073
  function inferMimeType(filePath) {
81721
- const ext = path33.extname(filePath).toLowerCase();
83074
+ const ext = path34.extname(filePath).toLowerCase();
81722
83075
  switch (ext) {
81723
83076
  case ".jpg":
81724
83077
  case ".jpeg":
@@ -81761,9 +83114,9 @@ var init_ingest_image = __esm({
81761
83114
  return;
81762
83115
  }
81763
83116
  const { project, reader, identity } = await getCliProjectContext();
81764
- const resolvedPath = path33.resolve(project.rootPath, imagePath);
83117
+ const resolvedPath = path34.resolve(project.rootPath, imagePath);
81765
83118
  const base642 = readFileSync16(resolvedPath).toString("base64");
81766
- const filename = path33.basename(resolvedPath);
83119
+ const filename = path34.basename(resolvedPath);
81767
83120
  const analysis = await analyzeImage({
81768
83121
  base64: base642,
81769
83122
  filename,
@@ -82027,7 +83380,7 @@ __export(background_exports, {
82027
83380
  doStart: () => doStart,
82028
83381
  doStop: () => doStop
82029
83382
  });
82030
- import * as fs22 from "fs";
83383
+ import * as fs23 from "fs";
82031
83384
  import { spawn as spawn4, execSync as execSync5 } from "child_process";
82032
83385
  import { randomBytes } from "crypto";
82033
83386
  function getMemorixDir() {
@@ -82045,7 +83398,7 @@ function getLogFilePath() {
82045
83398
  }
82046
83399
  function loadState() {
82047
83400
  try {
82048
- const data = fs22.readFileSync(getStateFilePath(), "utf-8");
83401
+ const data = fs23.readFileSync(getStateFilePath(), "utf-8");
82049
83402
  return JSON.parse(data);
82050
83403
  } catch {
82051
83404
  return null;
@@ -82053,12 +83406,12 @@ function loadState() {
82053
83406
  }
82054
83407
  function saveState(state) {
82055
83408
  const dir = getMemorixDir();
82056
- if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
82057
- 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));
82058
83411
  }
82059
83412
  function clearState() {
82060
83413
  try {
82061
- fs22.unlinkSync(getStateFilePath());
83414
+ fs23.unlinkSync(getStateFilePath());
82062
83415
  } catch {
82063
83416
  }
82064
83417
  }
@@ -82125,7 +83478,7 @@ async function doStart(port) {
82125
83478
  } else {
82126
83479
  try {
82127
83480
  const heartbeatPath = getMemorixDir() + "/background.heartbeat";
82128
- const hbData = fs22.readFileSync(heartbeatPath, "utf-8");
83481
+ const hbData = fs23.readFileSync(heartbeatPath, "utf-8");
82129
83482
  const hb = JSON.parse(hbData);
82130
83483
  const age = Date.now() - hb.heartbeatAt;
82131
83484
  if (age < 12e4) {
@@ -82133,7 +83486,7 @@ async function doStart(port) {
82133
83486
  console.log(" The control plane likely crashed. Auto-restarting...");
82134
83487
  }
82135
83488
  try {
82136
- fs22.unlinkSync(heartbeatPath);
83489
+ fs23.unlinkSync(heartbeatPath);
82137
83490
  } catch {
82138
83491
  }
82139
83492
  } catch {
@@ -82154,19 +83507,19 @@ async function doStart(port) {
82154
83507
  }
82155
83508
  try {
82156
83509
  const readyFile = getMemorixDir() + "/background.ready";
82157
- if (fs22.existsSync(readyFile)) fs22.unlinkSync(readyFile);
83510
+ if (fs23.existsSync(readyFile)) fs23.unlinkSync(readyFile);
82158
83511
  } catch {
82159
83512
  }
82160
83513
  const logFile = getLogFilePath();
82161
83514
  const dir = getMemorixDir();
82162
- if (!fs22.existsSync(dir)) fs22.mkdirSync(dir, { recursive: true });
82163
- if (fs22.existsSync(logFile)) {
83515
+ if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
83516
+ if (fs23.existsSync(logFile)) {
82164
83517
  try {
82165
- fs22.renameSync(logFile, logFile + ".prev");
83518
+ fs23.renameSync(logFile, logFile + ".prev");
82166
83519
  } catch {
82167
83520
  }
82168
83521
  }
82169
- const logFd = fs22.openSync(logFile, "a");
83522
+ const logFd = fs23.openSync(logFile, "a");
82170
83523
  const cliEntry = process.argv[1];
82171
83524
  const child = spawn4(process.execPath, [cliEntry, "serve-http", "--port", String(port)], {
82172
83525
  detached: true,
@@ -82176,7 +83529,7 @@ async function doStart(port) {
82176
83529
  windowsHide: true
82177
83530
  });
82178
83531
  child.unref();
82179
- fs22.closeSync(logFd);
83532
+ fs23.closeSync(logFd);
82180
83533
  const pid = child.pid;
82181
83534
  if (!pid) {
82182
83535
  console.error("[ERROR] Failed to spawn background process");
@@ -82246,7 +83599,7 @@ async function doStop() {
82246
83599
  console.log(`Background process (PID ${state.pid}) is not running. Cleaning up state.`);
82247
83600
  clearState();
82248
83601
  try {
82249
- fs22.unlinkSync(getMemorixDir() + "/background.ready");
83602
+ fs23.unlinkSync(getMemorixDir() + "/background.ready");
82250
83603
  } catch {
82251
83604
  }
82252
83605
  return;
@@ -82265,7 +83618,7 @@ async function doStop() {
82265
83618
  }
82266
83619
  clearState();
82267
83620
  try {
82268
- fs22.unlinkSync(getMemorixDir() + "/background.ready");
83621
+ fs23.unlinkSync(getMemorixDir() + "/background.ready");
82269
83622
  } catch {
82270
83623
  }
82271
83624
  return;
@@ -82302,7 +83655,7 @@ async function doStop() {
82302
83655
  }
82303
83656
  clearState();
82304
83657
  try {
82305
- fs22.unlinkSync(getMemorixDir() + "/background.ready");
83658
+ fs23.unlinkSync(getMemorixDir() + "/background.ready");
82306
83659
  } catch {
82307
83660
  }
82308
83661
  console.log("[OK] Control plane stopped.");
@@ -82378,7 +83731,7 @@ async function doStatus() {
82378
83731
  console.log(" Process has exited. Cleaning up stale state...");
82379
83732
  try {
82380
83733
  const heartbeatPath = getMemorixDir() + "/background.heartbeat";
82381
- const hbData = fs22.readFileSync(heartbeatPath, "utf-8");
83734
+ const hbData = fs23.readFileSync(heartbeatPath, "utf-8");
82382
83735
  const hb = JSON.parse(hbData);
82383
83736
  const age = Date.now() - hb.heartbeatAt;
82384
83737
  if (age < 3e5) {
@@ -82419,26 +83772,26 @@ async function doEnsure(port) {
82419
83772
  }
82420
83773
  function doLogs(follow, lines) {
82421
83774
  const logFile = getLogFilePath();
82422
- if (!fs22.existsSync(logFile)) {
83775
+ if (!fs23.existsSync(logFile)) {
82423
83776
  console.log("No log file found. Start the background service first:");
82424
83777
  console.log(" memorix background start");
82425
83778
  return;
82426
83779
  }
82427
83780
  if (follow) {
82428
- const content = fs22.readFileSync(logFile, "utf-8");
83781
+ const content = fs23.readFileSync(logFile, "utf-8");
82429
83782
  const existingLines = content.split("\n");
82430
83783
  const tail = existingLines.slice(-lines);
82431
83784
  console.log(tail.join("\n"));
82432
83785
  console.log("--- Following log (Ctrl+C to stop) ---");
82433
- let position = fs22.statSync(logFile).size;
82434
- const watcher = fs22.watch(logFile, () => {
83786
+ let position = fs23.statSync(logFile).size;
83787
+ const watcher = fs23.watch(logFile, () => {
82435
83788
  try {
82436
- const stat = fs22.statSync(logFile);
83789
+ const stat = fs23.statSync(logFile);
82437
83790
  if (stat.size > position) {
82438
- const fd = fs22.openSync(logFile, "r");
83791
+ const fd = fs23.openSync(logFile, "r");
82439
83792
  const buf = Buffer.alloc(stat.size - position);
82440
- fs22.readSync(fd, buf, 0, buf.length, position);
82441
- fs22.closeSync(fd);
83793
+ fs23.readSync(fd, buf, 0, buf.length, position);
83794
+ fs23.closeSync(fd);
82442
83795
  process.stdout.write(buf.toString("utf-8"));
82443
83796
  position = stat.size;
82444
83797
  }
@@ -82448,7 +83801,7 @@ function doLogs(follow, lines) {
82448
83801
  setInterval(() => {
82449
83802
  }, 6e4);
82450
83803
  } else {
82451
- const content = fs22.readFileSync(logFile, "utf-8");
83804
+ const content = fs23.readFileSync(logFile, "utf-8");
82452
83805
  const allLines = content.split("\n");
82453
83806
  const tail = allLines.slice(-lines);
82454
83807
  console.log(tail.join("\n"));
@@ -82633,7 +83986,7 @@ function asRecordArray(value) {
82633
83986
  return Array.isArray(value) ? value.map(asRecord2).filter((entry) => entry !== null) : [];
82634
83987
  }
82635
83988
  function codexPluginPath() {
82636
- return `${homedir32()}/.codex/plugins/${CODEX_PLUGIN_NAME}`;
83989
+ return `${homedir32()}/plugins/${CODEX_PLUGIN_NAME}`;
82637
83990
  }
82638
83991
  function codexPluginMcpPath() {
82639
83992
  return `${codexPluginPath()}/.mcp.json`;
@@ -82652,7 +84005,10 @@ function isMemorixCodexPlugin(value) {
82652
84005
  }
82653
84006
  function parseCodexPluginList(output) {
82654
84007
  try {
82655
- const parsed = asRecord2(JSON.parse(output));
84008
+ const start = output.indexOf("{");
84009
+ const end = output.lastIndexOf("}");
84010
+ if (start < 0 || end < start) return null;
84011
+ const parsed = asRecord2(JSON.parse(output.slice(start, end + 1)));
82656
84012
  if (!parsed) return null;
82657
84013
  const entries = [...asRecordArray(parsed.installed), ...asRecordArray(parsed.available)];
82658
84014
  const plugin = entries.find(isMemorixCodexPlugin);
@@ -82795,7 +84151,7 @@ async function inspectCodexMarketplace() {
82795
84151
  }
82796
84152
  const source = asRecord2(entry.source);
82797
84153
  const sourcePath = typeof source?.path === "string" ? source.path : "";
82798
- const issues = source?.source === "local" && normalizeMarketplacePath(sourcePath) === ".codex/plugins/memorix" ? [] : ["codex-marketplace-entry-stale"];
84154
+ const issues = source?.source === "local" && normalizeMarketplacePath(sourcePath) === "plugins/memorix" ? [] : ["codex-marketplace-entry-stale"];
82799
84155
  return {
82800
84156
  scope: "global",
82801
84157
  kind: "marketplace",
@@ -83362,9 +84718,11 @@ async function repairAgentIntegrations(options2 = {}) {
83362
84718
  } else {
83363
84719
  if (!options2.dry) {
83364
84720
  await installPluginPackage({ agent: "codex" });
83365
- if (needsInstall) {
83366
- const install = tryInstallCodexPlugin();
83367
- if (!install.ok) skipped.push("codex:plugin:global:install-pending");
84721
+ const install = tryInstallCodexPlugin();
84722
+ if (install.ok) {
84723
+ await migrateLegacyCodexIntegration({ projectRoot });
84724
+ } else {
84725
+ skipped.push("codex:plugin:global:install-pending");
83368
84726
  }
83369
84727
  }
83370
84728
  changed.push("codex:plugin:global");
@@ -84023,7 +85381,7 @@ __export(dashboard_exports, {
84023
85381
  default: () => dashboard_default
84024
85382
  });
84025
85383
  import { fileURLToPath as fileURLToPath6 } from "url";
84026
- import path34 from "path";
85384
+ import path35 from "path";
84027
85385
  var dashboard_default;
84028
85386
  var init_dashboard = __esm({
84029
85387
  "src/cli/commands/dashboard.ts"() {
@@ -84053,8 +85411,8 @@ var init_dashboard = __esm({
84053
85411
  }
84054
85412
  const dataDir = await getProjectDataDir2(project.id);
84055
85413
  const port = parseInt(args.port, 10) || 3210;
84056
- const cliDir = path34.dirname(fileURLToPath6(import.meta.url));
84057
- const staticDir = path34.join(cliDir, "..", "dashboard", "static");
85414
+ const cliDir = path35.dirname(fileURLToPath6(import.meta.url));
85415
+ const staticDir = path35.join(cliDir, "..", "dashboard", "static");
84058
85416
  await startDashboard2(dataDir, port, staticDir, project.id, project.name, true, void 0, project.rootPath, true);
84059
85417
  await new Promise(() => {
84060
85418
  });
@@ -84310,12 +85668,12 @@ var uninstall_exports = {};
84310
85668
  __export(uninstall_exports, {
84311
85669
  default: () => uninstall_default
84312
85670
  });
84313
- import * as fs23 from "fs";
84314
- import * as path35 from "path";
85671
+ import * as fs24 from "fs";
85672
+ import * as path36 from "path";
84315
85673
  import * as os4 from "os";
84316
85674
  function exists(p2) {
84317
85675
  try {
84318
- fs23.accessSync(p2);
85676
+ fs24.accessSync(p2);
84319
85677
  return true;
84320
85678
  } catch {
84321
85679
  return false;
@@ -84324,7 +85682,7 @@ function exists(p2) {
84324
85682
  function checkJSON(p2) {
84325
85683
  if (!exists(p2)) return false;
84326
85684
  try {
84327
- const content = fs23.readFileSync(p2, "utf-8");
85685
+ const content = fs24.readFileSync(p2, "utf-8");
84328
85686
  const cfg = JSON.parse(content);
84329
85687
  const servers = cfg.mcpServers ?? cfg.mcp_servers ?? cfg.servers ?? {};
84330
85688
  return Object.keys(servers).some((k5) => k5.toLowerCase().includes("memorix"));
@@ -84335,7 +85693,7 @@ function checkJSON(p2) {
84335
85693
  function checkTOML(p2) {
84336
85694
  if (!exists(p2)) return false;
84337
85695
  try {
84338
- const content = fs23.readFileSync(p2, "utf-8");
85696
+ const content = fs24.readFileSync(p2, "utf-8");
84339
85697
  return /\[mcp_servers\.(?:memorix|Memorix)\]/.test(content);
84340
85698
  } catch {
84341
85699
  return false;
@@ -84345,124 +85703,124 @@ function getMCPConfigEntries(home, cwd) {
84345
85703
  const entries = [];
84346
85704
  entries.push({
84347
85705
  agent: "Claude Code",
84348
- path: path35.join(home, ".claude.json"),
85706
+ path: path36.join(home, ".claude.json"),
84349
85707
  kind: "global",
84350
85708
  format: "json",
84351
- detected: checkJSON(path35.join(home, ".claude.json")),
85709
+ detected: checkJSON(path36.join(home, ".claude.json")),
84352
85710
  note: 'Remove the "memorix" key from mcpServers in this file.'
84353
85711
  });
84354
85712
  entries.push({
84355
85713
  agent: "Claude Code",
84356
- path: path35.join(cwd, ".claude", "settings.json"),
85714
+ path: path36.join(cwd, ".claude", "settings.json"),
84357
85715
  kind: "project",
84358
85716
  format: "json",
84359
- detected: checkJSON(path35.join(cwd, ".claude", "settings.json")),
85717
+ detected: checkJSON(path36.join(cwd, ".claude", "settings.json")),
84360
85718
  note: 'Remove the "memorix" key from mcpServers in this file.'
84361
85719
  });
84362
85720
  entries.push({
84363
85721
  agent: "Cursor",
84364
- path: path35.join(home, ".cursor", "mcp.json"),
85722
+ path: path36.join(home, ".cursor", "mcp.json"),
84365
85723
  kind: "global",
84366
85724
  format: "json",
84367
- detected: checkJSON(path35.join(home, ".cursor", "mcp.json")),
85725
+ detected: checkJSON(path36.join(home, ".cursor", "mcp.json")),
84368
85726
  note: 'Remove the "memorix" key from mcpServers in this file.'
84369
85727
  });
84370
85728
  entries.push({
84371
85729
  agent: "Cursor",
84372
- path: path35.join(cwd, ".cursor", "mcp.json"),
85730
+ path: path36.join(cwd, ".cursor", "mcp.json"),
84373
85731
  kind: "project",
84374
85732
  format: "json",
84375
- detected: checkJSON(path35.join(cwd, ".cursor", "mcp.json")),
85733
+ detected: checkJSON(path36.join(cwd, ".cursor", "mcp.json")),
84376
85734
  note: 'Remove the "memorix" key from mcpServers in this file.'
84377
85735
  });
84378
85736
  entries.push({
84379
85737
  agent: "Windsurf",
84380
- path: path35.join(home, ".codeium", "windsurf", "mcp_config.json"),
85738
+ path: path36.join(home, ".codeium", "windsurf", "mcp_config.json"),
84381
85739
  kind: "global",
84382
85740
  format: "json",
84383
- detected: checkJSON(path35.join(home, ".codeium", "windsurf", "mcp_config.json")),
85741
+ detected: checkJSON(path36.join(home, ".codeium", "windsurf", "mcp_config.json")),
84384
85742
  note: 'Remove the "memorix" key from mcpServers in this file.'
84385
85743
  });
84386
85744
  entries.push({
84387
85745
  agent: "Codex",
84388
- path: path35.join(home, ".codex", "config.toml"),
85746
+ path: path36.join(home, ".codex", "config.toml"),
84389
85747
  kind: "global",
84390
85748
  format: "toml",
84391
- detected: checkTOML(path35.join(home, ".codex", "config.toml")),
85749
+ detected: checkTOML(path36.join(home, ".codex", "config.toml")),
84392
85750
  note: "Remove the [mcp_servers.memorix] section from this file."
84393
85751
  });
84394
85752
  entries.push({
84395
85753
  agent: "VS Code / Copilot",
84396
- path: path35.join(home, ".vscode", "mcp.json"),
85754
+ path: path36.join(home, ".vscode", "mcp.json"),
84397
85755
  kind: "global",
84398
85756
  format: "json",
84399
- detected: checkJSON(path35.join(home, ".vscode", "mcp.json")),
85757
+ detected: checkJSON(path36.join(home, ".vscode", "mcp.json")),
84400
85758
  note: 'Remove the "memorix" key from servers in this file.'
84401
85759
  });
84402
85760
  entries.push({
84403
85761
  agent: "VS Code / Copilot",
84404
- path: path35.join(cwd, ".vscode", "mcp.json"),
85762
+ path: path36.join(cwd, ".vscode", "mcp.json"),
84405
85763
  kind: "project",
84406
85764
  format: "json",
84407
- detected: checkJSON(path35.join(cwd, ".vscode", "mcp.json")),
85765
+ detected: checkJSON(path36.join(cwd, ".vscode", "mcp.json")),
84408
85766
  note: 'Remove the "memorix" key from servers in this file.'
84409
85767
  });
84410
85768
  entries.push({
84411
85769
  agent: "Kiro",
84412
- path: path35.join(home, ".kiro", "settings", "mcp.json"),
85770
+ path: path36.join(home, ".kiro", "settings", "mcp.json"),
84413
85771
  kind: "global",
84414
85772
  format: "json",
84415
- detected: checkJSON(path35.join(home, ".kiro", "settings", "mcp.json")),
85773
+ detected: checkJSON(path36.join(home, ".kiro", "settings", "mcp.json")),
84416
85774
  note: 'Remove the "memorix" key from mcpServers in this file.'
84417
85775
  });
84418
85776
  entries.push({
84419
85777
  agent: "Kiro",
84420
- path: path35.join(cwd, ".kiro", "settings", "mcp.json"),
85778
+ path: path36.join(cwd, ".kiro", "settings", "mcp.json"),
84421
85779
  kind: "project",
84422
85780
  format: "json",
84423
- detected: checkJSON(path35.join(cwd, ".kiro", "settings", "mcp.json")),
85781
+ detected: checkJSON(path36.join(cwd, ".kiro", "settings", "mcp.json")),
84424
85782
  note: 'Remove the "memorix" key from mcpServers in this file.'
84425
85783
  });
84426
85784
  entries.push({
84427
85785
  agent: "Gemini CLI",
84428
- path: path35.join(home, ".gemini", "settings.json"),
85786
+ path: path36.join(home, ".gemini", "settings.json"),
84429
85787
  kind: "global",
84430
85788
  format: "json",
84431
- detected: checkJSON(path35.join(home, ".gemini", "settings.json")),
85789
+ detected: checkJSON(path36.join(home, ".gemini", "settings.json")),
84432
85790
  note: 'Remove the "memorix" key from mcpServers in this file.'
84433
85791
  });
84434
85792
  entries.push({
84435
85793
  agent: "Antigravity",
84436
- path: path35.join(home, ".gemini", "config", "mcp_config.json"),
85794
+ path: path36.join(home, ".gemini", "config", "mcp_config.json"),
84437
85795
  kind: "global",
84438
85796
  format: "json",
84439
- detected: checkJSON(path35.join(home, ".gemini", "config", "mcp_config.json")),
85797
+ detected: checkJSON(path36.join(home, ".gemini", "config", "mcp_config.json")),
84440
85798
  note: 'Remove the "memorix" key from mcpServers in this file.'
84441
85799
  });
84442
85800
  entries.push({
84443
85801
  agent: "Antigravity",
84444
- path: path35.join(home, ".gemini", "config", "hooks.json"),
85802
+ path: path36.join(home, ".gemini", "config", "hooks.json"),
84445
85803
  kind: "global",
84446
85804
  format: "json",
84447
- detected: exists(path35.join(home, ".gemini", "config", "hooks.json")),
85805
+ detected: exists(path36.join(home, ".gemini", "config", "hooks.json")),
84448
85806
  note: 'Remove the "memorix" hook group from this file.'
84449
85807
  });
84450
85808
  entries.push({
84451
85809
  agent: "Antigravity",
84452
- path: path35.join(home, ".gemini", "config", "plugins", "memorix", "plugin.json"),
85810
+ path: path36.join(home, ".gemini", "config", "plugins", "memorix", "plugin.json"),
84453
85811
  kind: "global",
84454
85812
  format: "json",
84455
- detected: exists(path35.join(home, ".gemini", "config", "plugins", "memorix", "plugin.json")),
85813
+ detected: exists(path36.join(home, ".gemini", "config", "plugins", "memorix", "plugin.json")),
84456
85814
  note: "Delete the containing ~/.gemini/config/plugins/memorix plugin directory if you want to remove the Antigravity plugin package."
84457
85815
  });
84458
85816
  const traeCfg = (() => {
84459
85817
  if (process.platform === "win32") {
84460
- 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");
84461
85819
  }
84462
85820
  if (process.platform === "darwin") {
84463
- return path35.join(home, "Library", "Application Support", "Trae", "User", "mcp.json");
85821
+ return path36.join(home, "Library", "Application Support", "Trae", "User", "mcp.json");
84464
85822
  }
84465
- return path35.join(home, ".config", "Trae", "User", "mcp.json");
85823
+ return path36.join(home, ".config", "Trae", "User", "mcp.json");
84466
85824
  })();
84467
85825
  entries.push({
84468
85826
  agent: "Trae",
@@ -84475,9 +85833,9 @@ function getMCPConfigEntries(home, cwd) {
84475
85833
  return entries;
84476
85834
  }
84477
85835
  function checkBackground(home) {
84478
- const statePath = path35.join(home, ".memorix", "background.json");
85836
+ const statePath = path36.join(home, ".memorix", "background.json");
84479
85837
  try {
84480
- const data = fs23.readFileSync(statePath, "utf-8");
85838
+ const data = fs24.readFileSync(statePath, "utf-8");
84481
85839
  const state = JSON.parse(data);
84482
85840
  try {
84483
85841
  process.kill(state.pid, 0);
@@ -84616,7 +85974,7 @@ var init_uninstall = __esm({
84616
85974
  },
84617
85975
  async run({ args }) {
84618
85976
  const home = os4.homedir();
84619
- const memorixDir = path35.join(home, ".memorix");
85977
+ const memorixDir = path36.join(home, ".memorix");
84620
85978
  const dryRun = args["dry-run"];
84621
85979
  const yes = args.yes;
84622
85980
  const doHooks = args.hooks;
@@ -84744,7 +86102,7 @@ var init_uninstall = __esm({
84744
86102
  if (exists(memorixDir)) {
84745
86103
  console.log(`[DELETE] Removing ${memorixDir}...`);
84746
86104
  try {
84747
- fs23.rmSync(memorixDir, { recursive: true, force: true });
86105
+ fs24.rmSync(memorixDir, { recursive: true, force: true });
84748
86106
  console.log("[OK] Data directory deleted.");
84749
86107
  changes++;
84750
86108
  } catch (err) {
@@ -85115,24 +86473,24 @@ var init_claude_stream = __esm({
85115
86473
  });
85116
86474
 
85117
86475
  // src/orchestrate/adapters/claude.ts
85118
- import * as fs24 from "fs";
85119
- import * as path36 from "path";
86476
+ import * as fs25 from "fs";
86477
+ import * as path37 from "path";
85120
86478
  function resolveMcpConfigPath(projectDir2) {
85121
- const localPath = path36.join(projectDir2, ".claude", "settings.local.json");
86479
+ const localPath = path37.join(projectDir2, ".claude", "settings.local.json");
85122
86480
  try {
85123
- if (fs24.existsSync(localPath)) return localPath;
86481
+ if (fs25.existsSync(localPath)) return localPath;
85124
86482
  } catch {
85125
86483
  }
85126
- const settingsPath = path36.join(projectDir2, ".claude", "settings.json");
86484
+ const settingsPath = path37.join(projectDir2, ".claude", "settings.json");
85127
86485
  try {
85128
- if (fs24.existsSync(settingsPath)) return settingsPath;
86486
+ if (fs25.existsSync(settingsPath)) return settingsPath;
85129
86487
  } catch {
85130
86488
  }
85131
86489
  const mcpConfig = {
85132
86490
  mcpServers: {
85133
86491
  memorix: {
85134
86492
  command: process.execPath,
85135
- 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"]
85136
86494
  }
85137
86495
  }
85138
86496
  };
@@ -85142,10 +86500,10 @@ function resolveMcpConfigPath(projectDir2) {
85142
86500
  args: ["serve", "--transport", "stdio"]
85143
86501
  };
85144
86502
  try {
85145
- const claudeDir = path36.join(projectDir2, ".claude");
85146
- fs24.mkdirSync(claudeDir, { recursive: true });
85147
- const tempPath = path36.join(claudeDir, "settings.local.json");
85148
- 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");
85149
86507
  return tempPath;
85150
86508
  } catch {
85151
86509
  return null;
@@ -86561,9 +87919,9 @@ function writePipelineSummary(projectDir2, summary) {
86561
87919
  return null;
86562
87920
  }
86563
87921
  }
86564
- function safeWrite(path37, content) {
87922
+ function safeWrite(path38, content) {
86565
87923
  try {
86566
- writeFileSync9(path37, content, "utf-8");
87924
+ writeFileSync9(path38, content, "utf-8");
86567
87925
  } catch {
86568
87926
  }
86569
87927
  }
@@ -88034,8 +89392,8 @@ var init_orchestrate = __esm({
88034
89392
  const { getProjectDataDir: getProjectDataDir2 } = await Promise.resolve().then(() => (init_persistence(), persistence_exports));
88035
89393
  const { resolveAdapters: resolveAdapters2, parseAgentQuotas: parseAgentQuotas2, buildQuotaMap: buildQuotaMap2 } = await Promise.resolve().then(() => (init_adapters(), adapters_exports));
88036
89394
  const { runCoordinationLoop: runCoordinationLoop2 } = await Promise.resolve().then(() => (init_coordinator(), coordinator_exports));
88037
- const path37 = await import("path");
88038
- 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();
88039
89397
  const proj = detectProject2(projectDir2);
88040
89398
  if (!proj) {
88041
89399
  console.error("[ERROR] Not a git repository. Run `git init` first.");
@@ -89145,7 +90503,7 @@ var init_Panels = __esm({
89145
90503
  // src/cli/tui/ConfigureView.tsx
89146
90504
  import { useState as useState2, useEffect as useEffect2 } from "react";
89147
90505
  import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
89148
- import * as fs25 from "fs";
90506
+ import * as fs26 from "fs";
89149
90507
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
89150
90508
  function getConfigPath() {
89151
90509
  return `${process.env.HOME || process.env.USERPROFILE}/.memorix/config.json`;
@@ -89153,15 +90511,15 @@ function getConfigPath() {
89153
90511
  function loadConfig() {
89154
90512
  try {
89155
90513
  const p2 = getConfigPath();
89156
- 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"));
89157
90515
  } catch {
89158
90516
  }
89159
90517
  return {};
89160
90518
  }
89161
90519
  function saveConfig(config2) {
89162
90520
  const dir = `${process.env.HOME || process.env.USERPROFILE}/.memorix`;
89163
- if (!fs25.existsSync(dir)) fs25.mkdirSync(dir, { recursive: true });
89164
- 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));
89165
90523
  }
89166
90524
  function separator2(w3 = 50) {
89167
90525
  return SEP.thin.repeat(w3);
@@ -89874,7 +91232,7 @@ var init_session_service = __esm({
89874
91232
  });
89875
91233
 
89876
91234
  // src/cli/tui/data.ts
89877
- import * as fs26 from "fs";
91235
+ import * as fs27 from "fs";
89878
91236
  function formatSearchModeLabel(mode) {
89879
91237
  const normalized = (mode || "").toLowerCase();
89880
91238
  if (!normalized) return "Unknown";
@@ -90081,7 +91439,7 @@ async function getBackgroundStatus() {
90081
91439
  try {
90082
91440
  const home = process.env.HOME || process.env.USERPROFILE || "";
90083
91441
  const statePath = `${home.replace(/\\/g, "/")}/.memorix/background.json`;
90084
- if (!fs26.existsSync(statePath)) {
91442
+ if (!fs27.existsSync(statePath)) {
90085
91443
  try {
90086
91444
  const controller = new AbortController();
90087
91445
  const timer = setTimeout(() => controller.abort(), 2e3);
@@ -90102,7 +91460,7 @@ async function getBackgroundStatus() {
90102
91460
  }
90103
91461
  return result;
90104
91462
  }
90105
- const state = JSON.parse(fs26.readFileSync(statePath, "utf-8"));
91463
+ const state = JSON.parse(fs27.readFileSync(statePath, "utf-8"));
90106
91464
  result.pid = state.pid;
90107
91465
  result.port = state.port;
90108
91466
  result.startedAt = state.startedAt;
@@ -90193,8 +91551,8 @@ function detectMode() {
90193
91551
  try {
90194
91552
  const home = process.env.HOME || process.env.USERPROFILE || "";
90195
91553
  const statePath = `${home.replace(/\\/g, "/")}/.memorix/background.json`;
90196
- if (fs26.existsSync(statePath)) {
90197
- const state = JSON.parse(fs26.readFileSync(statePath, "utf-8"));
91554
+ if (fs27.existsSync(statePath)) {
91555
+ const state = JSON.parse(fs27.readFileSync(statePath, "utf-8"));
90198
91556
  try {
90199
91557
  process.kill(state.pid, 0);
90200
91558
  return { mode: "Background", detail: `port ${state.port}` };
@@ -92735,9 +94093,17 @@ var GUIDES = {
92735
94093
  "memorix memory recent [--limit 10]",
92736
94094
  "memorix memory resolve --ids 42,43 [--status resolved|archived]",
92737
94095
  "memorix memory consolidate --action preview|execute",
92738
- '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 "..."'
92739
94102
  ],
92740
- 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
+ ]
92741
94107
  },
92742
94108
  identity: {
92743
94109
  summary: "Select the active local actor for private memory and coordination commands.",