memorix 1.4.4 → 1.4.6

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 (90) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/CLAUDE.md +7 -3
  3. package/README.md +14 -4
  4. package/README.zh-CN.md +9 -2
  5. package/dist/cli/index.js +1802 -1138
  6. package/dist/index.js +1298 -991
  7. package/dist/{maintenance-jobs-B1-W0ssz.d.ts → maintenance-jobs-DVRF-46r.d.ts} +1 -1
  8. package/dist/maintenance-runner.d.ts +1 -1
  9. package/dist/maintenance-runner.js +1755 -829
  10. package/dist/media-audio-runner.js +1760 -835
  11. package/dist/media-video-runner.js +1755 -830
  12. package/dist/memcode-runtime/CHANGELOG.md +69 -0
  13. package/dist/sdk.js +1290 -990
  14. package/dist/types.d.ts +7 -1
  15. package/dist/vector-backfill-runner.d.ts +1 -1
  16. package/dist/vector-backfill-runner.js +1751 -826
  17. package/docs/1.4.5-AGENT-AUTO-MEMORY-RESEARCH.md +95 -0
  18. package/docs/AGENT_OPERATOR_PLAYBOOK.md +3 -2
  19. package/docs/API_REFERENCE.md +23 -4
  20. package/docs/CONFIGURATION.md +17 -3
  21. package/docs/INTEGRATIONS.md +9 -2
  22. package/docs/KNOWN_ISSUES_AND_ROADMAP.md +1 -0
  23. package/docs/MEMCODE.md +1 -1
  24. package/docs/SETUP.md +14 -4
  25. package/llms-full.txt +5 -4
  26. package/llms.txt +1 -1
  27. package/package.json +1 -1
  28. package/plugins/antigravity/memorix/mcp_config.json +3 -1
  29. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  30. package/plugins/claude/memorix/.mcp.json +1 -1
  31. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  32. package/plugins/codebuddy/memorix/.mcp.json +1 -1
  33. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  34. package/plugins/codex/memorix/.mcp.json +1 -1
  35. package/plugins/copilot/memorix/.mcp.json +1 -1
  36. package/plugins/copilot/memorix/plugin.json +1 -1
  37. package/plugins/gemini/memorix/gemini-extension.json +4 -2
  38. package/plugins/omp/memorix/package.json +1 -1
  39. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  40. package/plugins/openclaw/memorix/.mcp.json +3 -1
  41. package/plugins/pi/memorix/package.json +1 -1
  42. package/server.json +2 -2
  43. package/src/cli/commands/agent-integrations.ts +7 -1
  44. package/src/cli/commands/dashboard.ts +14 -3
  45. package/src/cli/commands/hooks-install.ts +2 -0
  46. package/src/cli/commands/hooks-preview.ts +5 -0
  47. package/src/cli/commands/ingest-commit.ts +47 -3
  48. package/src/cli/commands/integrate.ts +2 -0
  49. package/src/cli/commands/memory.ts +17 -4
  50. package/src/cli/commands/purge.ts +120 -0
  51. package/src/cli/commands/serve-http.ts +39 -5
  52. package/src/cli/commands/setup.ts +60 -3
  53. package/src/cli/commands/uninstall.ts +20 -0
  54. package/src/cli/index.ts +3 -804
  55. package/src/codegraph/auto-context.ts +82 -1
  56. package/src/config/yaml-loader.ts +3 -8
  57. package/src/config.ts +0 -5
  58. package/src/evaluation/session-replay.ts +98 -0
  59. package/src/git/extractor.ts +5 -3
  60. package/src/hooks/installers/index.ts +58 -2
  61. package/src/hooks/types.ts +2 -0
  62. package/src/integrations/registry.ts +9 -0
  63. package/src/knowledge/workset.ts +58 -0
  64. package/src/memory/long-term.ts +97 -2
  65. package/src/runtime/control-plane-maintenance.ts +1 -0
  66. package/src/runtime/isolated-maintenance.ts +1 -0
  67. package/src/runtime/lifecycle.ts +19 -0
  68. package/src/runtime/maintenance-jobs.ts +1 -0
  69. package/src/runtime/project-maintenance.ts +8 -0
  70. package/src/search/surfaced-registry.ts +62 -0
  71. package/src/server.ts +74 -14
  72. package/src/store/orama-store.ts +17 -1
  73. package/src/types.ts +7 -1
  74. package/src/workspace/mcp-adapters/dsh.ts +147 -0
  75. package/src/cli/commands/audit-list.ts +0 -89
  76. package/src/cli/commands/purge-all-memory.ts +0 -85
  77. package/src/cli/commands/purge-project-memory.ts +0 -83
  78. package/src/cli/commands/uninstall-project-artifacts.ts +0 -86
  79. package/src/cli/tui/Sidebar.tsx +0 -179
  80. package/src/cli/tui/interactive-commands.ts +0 -261
  81. package/src/cli/tui/markdown-render.tsx +0 -371
  82. package/src/cli/tui/use-mouse.ts +0 -157
  83. package/src/cli/tui/useNavigation.ts +0 -56
  84. package/src/orchestrate/context-compact.ts +0 -188
  85. package/src/team/file-locks.ts +0 -173
  86. package/src/team/index.ts +0 -23
  87. package/src/team/messages.ts +0 -203
  88. package/src/team/persistence.ts +0 -96
  89. package/src/team/registry.ts +0 -158
  90. package/src/team/tasks.ts +0 -211
package/dist/sdk.js CHANGED
@@ -3393,7 +3393,6 @@ __export(config_exports, {
3393
3393
  getLLMProvider: () => getLLMProvider,
3394
3394
  getLoadedEnvFiles: () => getLoadedEnvFiles,
3395
3395
  getServerConfig: () => getServerConfig,
3396
- getTeamConfig: () => getTeamConfig,
3397
3396
  loadDotenv: () => loadDotenv,
3398
3397
  loadFileConfig: () => loadFileConfig,
3399
3398
  loadYamlConfig: () => loadYamlConfig,
@@ -3465,14 +3464,10 @@ function getServerConfig() {
3465
3464
  port: server.port
3466
3465
  };
3467
3466
  }
3468
- function getTeamConfig() {
3469
- return loadYamlConfig().team ?? {};
3470
- }
3471
3467
  var init_config = __esm({
3472
3468
  "src/config.ts"() {
3473
3469
  "use strict";
3474
3470
  init_esm_shims();
3475
- init_yaml_loader();
3476
3471
  init_resolved_config();
3477
3472
  init_dotenv_loader();
3478
3473
  init_legacy_loader();
@@ -5757,9 +5752,9 @@ async function saveRegistry(baseDir) {
5757
5752
  await fs7.mkdir(path9.dirname(filePath), { recursive: true });
5758
5753
  await fs7.writeFile(filePath, JSON.stringify(registryCache, null, 2), "utf-8");
5759
5754
  }
5760
- function findMatchingGroup(registry, projectInfo) {
5755
+ function findMatchingGroup(registry2, projectInfo) {
5761
5756
  const normalizedRoot = normalizePath(projectInfo.rootPath);
5762
- for (const group of registry.groups) {
5757
+ for (const group of registry2.groups) {
5763
5758
  if (group.aliases.includes(projectInfo.id)) return group;
5764
5759
  if (group.rootPaths.some((rp) => rp === normalizedRoot)) return group;
5765
5760
  if (projectInfo.gitRemote && group.gitRemote && group.gitRemote === projectInfo.gitRemote) {
@@ -5772,9 +5767,9 @@ function selectCanonical(aliases) {
5772
5767
  return [...aliases].sort((a, b) => idPriority(b) - idPriority(a))[0];
5773
5768
  }
5774
5769
  async function registerAlias(projectInfo, baseDir) {
5775
- const registry = await loadRegistry(baseDir);
5770
+ const registry2 = await loadRegistry(baseDir);
5776
5771
  const normalizedRoot = normalizePath(projectInfo.rootPath);
5777
- const existingGroup = findMatchingGroup(registry, projectInfo);
5772
+ const existingGroup = findMatchingGroup(registry2, projectInfo);
5778
5773
  if (existingGroup) {
5779
5774
  let changed = false;
5780
5775
  if (!existingGroup.aliases.includes(projectInfo.id)) {
@@ -5805,13 +5800,13 @@ async function registerAlias(projectInfo, baseDir) {
5805
5800
  rootPaths: [normalizedRoot],
5806
5801
  ...projectInfo.gitRemote ? { gitRemote: projectInfo.gitRemote } : {}
5807
5802
  };
5808
- registry.groups.push(newGroup);
5803
+ registry2.groups.push(newGroup);
5809
5804
  await saveRegistry(baseDir);
5810
5805
  return newGroup.canonical;
5811
5806
  }
5812
5807
  async function resolveAliases(projectId, baseDir) {
5813
- const registry = await loadRegistry(baseDir);
5814
- for (const group of registry.groups) {
5808
+ const registry2 = await loadRegistry(baseDir);
5809
+ for (const group of registry2.groups) {
5815
5810
  if (group.aliases.includes(projectId) || group.canonical === projectId) {
5816
5811
  return [...group.aliases];
5817
5812
  }
@@ -5819,8 +5814,8 @@ async function resolveAliases(projectId, baseDir) {
5819
5814
  return [projectId];
5820
5815
  }
5821
5816
  async function getCanonicalId(projectId, baseDir) {
5822
- const registry = await loadRegistry(baseDir);
5823
- for (const group of registry.groups) {
5817
+ const registry2 = await loadRegistry(baseDir);
5818
+ for (const group of registry2.groups) {
5824
5819
  if (group.aliases.includes(projectId) || group.canonical === projectId) {
5825
5820
  return group.canonical;
5826
5821
  }
@@ -5828,12 +5823,12 @@ async function getCanonicalId(projectId, baseDir) {
5828
5823
  return projectId;
5829
5824
  }
5830
5825
  async function getAllAliasGroups(baseDir) {
5831
- const registry = await loadRegistry(baseDir);
5832
- return registry.groups;
5826
+ const registry2 = await loadRegistry(baseDir);
5827
+ return registry2.groups;
5833
5828
  }
5834
5829
  async function autoMergeByBaseName(observedIds, baseDir) {
5835
5830
  if (observedIds.length <= 1) return 0;
5836
- const registry = await loadRegistry(baseDir);
5831
+ const registry2 = await loadRegistry(baseDir);
5837
5832
  const byBaseName = /* @__PURE__ */ new Map();
5838
5833
  for (const id of observedIds) {
5839
5834
  const baseName = id.split("/").pop() ?? id;
@@ -5846,7 +5841,7 @@ async function autoMergeByBaseName(observedIds, baseDir) {
5846
5841
  const existingGroups = /* @__PURE__ */ new Set();
5847
5842
  const ungroupedIds = [];
5848
5843
  for (const id of ids) {
5849
- const groupIdx = registry.groups.findIndex(
5844
+ const groupIdx = registry2.groups.findIndex(
5850
5845
  (g) => g.aliases.includes(id) || g.canonical === id
5851
5846
  );
5852
5847
  if (groupIdx >= 0) {
@@ -5860,7 +5855,7 @@ async function autoMergeByBaseName(observedIds, baseDir) {
5860
5855
  const canonical = selectCanonical(allIdsInGroup);
5861
5856
  if (existingGroups.size > 0) {
5862
5857
  const primaryIdx = [...existingGroups][0];
5863
- const primaryGroup = registry.groups[primaryIdx];
5858
+ const primaryGroup = registry2.groups[primaryIdx];
5864
5859
  for (const id of allIdsInGroup) {
5865
5860
  if (!primaryGroup.aliases.includes(id)) {
5866
5861
  primaryGroup.aliases.push(id);
@@ -5868,7 +5863,7 @@ async function autoMergeByBaseName(observedIds, baseDir) {
5868
5863
  }
5869
5864
  const otherIdxs = [...existingGroups].slice(1).sort((a, b) => b - a);
5870
5865
  for (const idx of otherIdxs) {
5871
- const other = registry.groups[idx];
5866
+ const other = registry2.groups[idx];
5872
5867
  for (const alias of other.aliases) {
5873
5868
  if (!primaryGroup.aliases.includes(alias)) {
5874
5869
  primaryGroup.aliases.push(alias);
@@ -5882,12 +5877,12 @@ async function autoMergeByBaseName(observedIds, baseDir) {
5882
5877
  if (other.gitRemote && !primaryGroup.gitRemote) {
5883
5878
  primaryGroup.gitRemote = other.gitRemote;
5884
5879
  }
5885
- registry.groups.splice(idx, 1);
5880
+ registry2.groups.splice(idx, 1);
5886
5881
  }
5887
5882
  primaryGroup.canonical = selectCanonical(primaryGroup.aliases);
5888
5883
  mergeCount++;
5889
5884
  } else {
5890
- registry.groups.push({
5885
+ registry2.groups.push({
5891
5886
  canonical,
5892
5887
  aliases: allIdsInGroup,
5893
5888
  rootPaths: []
@@ -6523,7 +6518,7 @@ async function searchObservations(options) {
6523
6518
  const expandedEmbeddingQuery = quality === "thorough" && tier === "heavy" ? await maybeExpandSearchQuery(options.query) : options.query;
6524
6519
  mark("queryExpansion");
6525
6520
  const intentResult = quality === "fast" || !hasQuery ? null : detectQueryIntent(originalQuery);
6526
- const requestLimit = projectIds ? (options.limit ?? 20) * 3 : options.limit ?? 20;
6521
+ const requestLimit = projectIds || options.surfacedIds && options.surfacedIds.length > 0 ? (options.limit ?? 20) * 3 : options.limit ?? 20;
6527
6522
  const defaultBoost = {
6528
6523
  title: 3,
6529
6524
  entityName: 2,
@@ -6755,6 +6750,14 @@ async function searchObservations(options) {
6755
6750
  });
6756
6751
  intermediate.sort((a, b) => b.score - a.score);
6757
6752
  }
6753
+ if (options.surfacedIds && options.surfacedIds.length > 0) {
6754
+ const SURFACED_PENALTY = 0.5;
6755
+ const surfaced = new Set(options.surfacedIds);
6756
+ intermediate = intermediate.map(
6757
+ (entry) => surfaced.has(entry.id) ? { ...entry, score: (entry.score ?? 0) * SURFACED_PENALTY } : entry
6758
+ );
6759
+ intermediate.sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
6760
+ }
6758
6761
  if (options.since) {
6759
6762
  const sinceDate = new Date(options.since).getTime();
6760
6763
  intermediate = intermediate.filter((e2) => new Date(e2.rawTime).getTime() >= sinceDate);
@@ -7746,7 +7749,8 @@ var init_maintenance_jobs = __esm({
7746
7749
  "claim-requalification",
7747
7750
  "knowledge-compile",
7748
7751
  "knowledge-lint",
7749
- "workflow-index"
7752
+ "workflow-index",
7753
+ "long-term-maintenance"
7750
7754
  ];
7751
7755
  DEFAULT_MAX_ATTEMPTS = 8;
7752
7756
  DEFAULT_LEASE_MS = 3e4;
@@ -8155,6 +8159,7 @@ __export(lifecycle_exports, {
8155
8159
  enqueueClaimRequalification: () => enqueueClaimRequalification,
8156
8160
  enqueueCodegraphRefresh: () => enqueueCodegraphRefresh,
8157
8161
  enqueueKnowledgeFollowups: () => enqueueKnowledgeFollowups,
8162
+ enqueueLongTermMaintenance: () => enqueueLongTermMaintenance,
8158
8163
  enqueueObservationQualification: () => enqueueObservationQualification
8159
8164
  });
8160
8165
  function queueFor(input) {
@@ -8198,6 +8203,14 @@ function enqueueObservationQualification(input) {
8198
8203
  payload: { source: input.source, limit: 100 }
8199
8204
  });
8200
8205
  }
8206
+ function enqueueLongTermMaintenance(input) {
8207
+ queueFor(input).enqueue({
8208
+ projectId: input.projectId,
8209
+ kind: "long-term-maintenance",
8210
+ dedupeKey: "long-term-maintenance",
8211
+ payload: { source: input.source }
8212
+ });
8213
+ }
8201
8214
  function enqueueKnowledgeFollowups(input) {
8202
8215
  const queue = queueFor(input);
8203
8216
  const payload = {
@@ -8377,7 +8390,8 @@ var init_isolated_maintenance = __esm({
8377
8390
  "claim-requalification",
8378
8391
  "knowledge-compile",
8379
8392
  "knowledge-lint",
8380
- "workflow-index"
8393
+ "workflow-index",
8394
+ "long-term-maintenance"
8381
8395
  ];
8382
8396
  DEFAULT_TIMEOUT_MS = 5 * 6e4;
8383
8397
  MAX_CHILD_OUTPUT_BYTES = 1e6;
@@ -144224,6 +144238,889 @@ var init_retention = __esm({
144224
144238
  }
144225
144239
  });
144226
144240
 
144241
+ // src/memory/owner.ts
144242
+ var owner_exports = {};
144243
+ __export(owner_exports, {
144244
+ resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
144245
+ });
144246
+ import { randomUUID as randomUUID6 } from "crypto";
144247
+ import { promises as fs12 } from "fs";
144248
+ import path19 from "path";
144249
+ function ownerPath(dataDir) {
144250
+ const resolved = path19.resolve(dataDir);
144251
+ const home = path19.basename(resolved).toLocaleLowerCase("en-US") === "data" ? path19.dirname(resolved) : resolved;
144252
+ return path19.join(home, "memorix-user.json");
144253
+ }
144254
+ function normalizedOwnerId(value) {
144255
+ const trimmed = value?.trim();
144256
+ return trimmed && ID_PATTERN.test(trimmed) ? trimmed : void 0;
144257
+ }
144258
+ async function readOwnerFile(filePath) {
144259
+ try {
144260
+ const value = JSON.parse(await fs12.readFile(filePath, "utf8"));
144261
+ const id = typeof value.id === "string" ? normalizedOwnerId(value.id) : void 0;
144262
+ return id ? { id, source: "local-file" } : void 0;
144263
+ } catch {
144264
+ return void 0;
144265
+ }
144266
+ }
144267
+ async function resolveLocalMemoryOwner(dataDir, options = {}) {
144268
+ const configured = normalizedOwnerId(process.env.MEMORIX_USER_ID);
144269
+ if (configured) return { id: configured, source: "environment" };
144270
+ const filePath = ownerPath(dataDir);
144271
+ const existing = await readOwnerFile(filePath);
144272
+ if (existing || !options.create) return existing;
144273
+ await fs12.mkdir(path19.dirname(filePath), { recursive: true });
144274
+ const created = {
144275
+ version: 1,
144276
+ id: "local-" + randomUUID6(),
144277
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
144278
+ };
144279
+ try {
144280
+ await fs12.writeFile(filePath, JSON.stringify(created, null, 2) + "\n", { encoding: "utf8", flag: "wx" });
144281
+ return { id: created.id, source: "local-file" };
144282
+ } catch (error) {
144283
+ if (error?.code !== "EEXIST") throw error;
144284
+ const concurrent = await readOwnerFile(filePath);
144285
+ if (concurrent) return concurrent;
144286
+ throw new Error("Memorix could not establish a valid local memory owner identity.");
144287
+ }
144288
+ }
144289
+ var ID_PATTERN;
144290
+ var init_owner = __esm({
144291
+ "src/memory/owner.ts"() {
144292
+ "use strict";
144293
+ init_esm_shims();
144294
+ ID_PATTERN = /^[A-Za-z0-9:_-]{3,160}$/;
144295
+ }
144296
+ });
144297
+
144298
+ // src/memory/long-term-store.ts
144299
+ import { randomUUID as randomUUID7 } from "crypto";
144300
+ function optionalText2(value) {
144301
+ return typeof value === "string" && value.trim() ? value : void 0;
144302
+ }
144303
+ function arrayValue2(value) {
144304
+ if (typeof value !== "string" || !value) return [];
144305
+ try {
144306
+ const parsed = JSON.parse(value);
144307
+ return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
144308
+ } catch {
144309
+ return [];
144310
+ }
144311
+ }
144312
+ function rowToMemory(row) {
144313
+ return {
144314
+ id: row.id,
144315
+ originProjectId: row.originProjectId,
144316
+ ownerId: row.ownerId,
144317
+ scope: row.scope,
144318
+ kind: row.kind,
144319
+ state: row.state,
144320
+ portability: row.portability,
144321
+ title: row.title,
144322
+ content: row.content,
144323
+ facts: arrayValue2(row.factsJson),
144324
+ tags: arrayValue2(row.tagsJson),
144325
+ ...optionalText2(row.applicability) ? { applicability: row.applicability } : {},
144326
+ origin: row.origin,
144327
+ createdAt: row.createdAt,
144328
+ updatedAt: row.updatedAt,
144329
+ ...optionalText2(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
144330
+ ...optionalText2(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
144331
+ ...optionalText2(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
144332
+ ...optionalText2(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
144333
+ ...optionalText2(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
144334
+ accessCount: Number(row.accessCount ?? 0),
144335
+ ...optionalText2(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
144336
+ };
144337
+ }
144338
+ function rowToEvidence(row) {
144339
+ return {
144340
+ id: row.id,
144341
+ memoryId: row.memoryId,
144342
+ kind: row.kind,
144343
+ referenceId: row.referenceId,
144344
+ relation: row.relation,
144345
+ ...optionalText2(row.locator) ? { locator: row.locator } : {},
144346
+ ...optionalText2(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
144347
+ createdAt: row.createdAt
144348
+ };
144349
+ }
144350
+ function rowToEvent(row) {
144351
+ return {
144352
+ id: row.id,
144353
+ memoryId: row.memoryId,
144354
+ kind: row.kind,
144355
+ ...optionalText2(row.fromState) ? { fromState: row.fromState } : {},
144356
+ ...optionalText2(row.toState) ? { toState: row.toState } : {},
144357
+ ...optionalText2(row.detail) ? { detail: row.detail } : {},
144358
+ createdAt: row.createdAt
144359
+ };
144360
+ }
144361
+ var LongTermMemoryStore;
144362
+ var init_long_term_store = __esm({
144363
+ "src/memory/long-term-store.ts"() {
144364
+ "use strict";
144365
+ init_esm_shims();
144366
+ init_sqlite_db();
144367
+ LongTermMemoryStore = class {
144368
+ db = null;
144369
+ async init(dataDir) {
144370
+ this.db = getDatabase(dataDir);
144371
+ }
144372
+ transaction(fn) {
144373
+ return this.db.transaction(fn)();
144374
+ }
144375
+ get(id) {
144376
+ const row = this.db.prepare("SELECT * FROM long_term_memories WHERE id = ?").get(id);
144377
+ return row ? rowToMemory(row) : void 0;
144378
+ }
144379
+ list(options = {}) {
144380
+ const limit2 = Math.max(1, Math.min(1e3, Math.floor(options.limit ?? 500)));
144381
+ const clauses = [];
144382
+ const params = [];
144383
+ if (options.ownerId) {
144384
+ clauses.push("ownerId = ?");
144385
+ params.push(options.ownerId);
144386
+ }
144387
+ if (options.originProjectId) {
144388
+ clauses.push("originProjectId = ?");
144389
+ params.push(options.originProjectId);
144390
+ }
144391
+ const where = clauses.length ? " WHERE " + clauses.join(" AND ") : "";
144392
+ const rows = this.db.prepare(
144393
+ "SELECT * FROM long_term_memories" + where + " ORDER BY updatedAt DESC, id LIMIT ?"
144394
+ ).all(...params, limit2);
144395
+ return rows.map(rowToMemory);
144396
+ }
144397
+ insert(memory) {
144398
+ this.db.prepare(`
144399
+ INSERT INTO long_term_memories (
144400
+ id, originProjectId, ownerId, scope, kind, state, portability,
144401
+ title, content, factsJson, tagsJson, applicability, origin,
144402
+ createdAt, updatedAt, qualifiedAt, approvedAt, archivedAt,
144403
+ supersededBy, lastValidatedAt, accessCount, lastAccessedAt
144404
+ ) VALUES (
144405
+ @id, @originProjectId, @ownerId, @scope, @kind, @state, @portability,
144406
+ @title, @content, @factsJson, @tagsJson, @applicability, @origin,
144407
+ @createdAt, @updatedAt, @qualifiedAt, @approvedAt, @archivedAt,
144408
+ @supersededBy, @lastValidatedAt, @accessCount, @lastAccessedAt
144409
+ )
144410
+ `).run({
144411
+ ...memory,
144412
+ factsJson: JSON.stringify(memory.facts),
144413
+ tagsJson: JSON.stringify(memory.tags),
144414
+ applicability: memory.applicability ?? null,
144415
+ qualifiedAt: memory.qualifiedAt ?? null,
144416
+ approvedAt: memory.approvedAt ?? null,
144417
+ archivedAt: memory.archivedAt ?? null,
144418
+ supersededBy: memory.supersededBy ?? null,
144419
+ lastValidatedAt: memory.lastValidatedAt ?? null,
144420
+ lastAccessedAt: memory.lastAccessedAt ?? null
144421
+ });
144422
+ }
144423
+ update(memory) {
144424
+ this.db.prepare(`
144425
+ UPDATE long_term_memories SET
144426
+ scope = @scope,
144427
+ kind = @kind,
144428
+ state = @state,
144429
+ portability = @portability,
144430
+ title = @title,
144431
+ content = @content,
144432
+ factsJson = @factsJson,
144433
+ tagsJson = @tagsJson,
144434
+ applicability = @applicability,
144435
+ updatedAt = @updatedAt,
144436
+ qualifiedAt = @qualifiedAt,
144437
+ approvedAt = @approvedAt,
144438
+ archivedAt = @archivedAt,
144439
+ supersededBy = @supersededBy,
144440
+ lastValidatedAt = @lastValidatedAt,
144441
+ accessCount = @accessCount,
144442
+ lastAccessedAt = @lastAccessedAt
144443
+ WHERE id = @id
144444
+ `).run({
144445
+ ...memory,
144446
+ factsJson: JSON.stringify(memory.facts),
144447
+ tagsJson: JSON.stringify(memory.tags),
144448
+ applicability: memory.applicability ?? null,
144449
+ qualifiedAt: memory.qualifiedAt ?? null,
144450
+ approvedAt: memory.approvedAt ?? null,
144451
+ archivedAt: memory.archivedAt ?? null,
144452
+ supersededBy: memory.supersededBy ?? null,
144453
+ lastValidatedAt: memory.lastValidatedAt ?? null,
144454
+ lastAccessedAt: memory.lastAccessedAt ?? null
144455
+ });
144456
+ }
144457
+ insertEvidence(input) {
144458
+ const evidence = {
144459
+ id: randomUUID7(),
144460
+ ...input,
144461
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
144462
+ };
144463
+ this.db.prepare(`
144464
+ INSERT INTO long_term_memory_evidence (
144465
+ id, memoryId, kind, referenceId, relation, locator, capturedHash, createdAt
144466
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
144467
+ `).run(
144468
+ evidence.id,
144469
+ evidence.memoryId,
144470
+ evidence.kind,
144471
+ evidence.referenceId,
144472
+ evidence.relation,
144473
+ evidence.locator ?? null,
144474
+ evidence.capturedHash ?? null,
144475
+ evidence.createdAt
144476
+ );
144477
+ return evidence;
144478
+ }
144479
+ listEvidence(memoryId) {
144480
+ return this.db.prepare(`
144481
+ SELECT * FROM long_term_memory_evidence WHERE memoryId = ? ORDER BY createdAt ASC, id
144482
+ `).all(memoryId).map(rowToEvidence);
144483
+ }
144484
+ recordEvent(input) {
144485
+ const event = {
144486
+ id: randomUUID7(),
144487
+ ...input,
144488
+ createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
144489
+ };
144490
+ this.db.prepare(`
144491
+ INSERT INTO long_term_memory_events (id, memoryId, kind, fromState, toState, detail, createdAt)
144492
+ VALUES (?, ?, ?, ?, ?, ?, ?)
144493
+ `).run(
144494
+ event.id,
144495
+ event.memoryId,
144496
+ event.kind,
144497
+ event.fromState ?? null,
144498
+ event.toState ?? null,
144499
+ event.detail ?? null,
144500
+ event.createdAt
144501
+ );
144502
+ return event;
144503
+ }
144504
+ listEvents(memoryId) {
144505
+ return this.db.prepare(`
144506
+ SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
144507
+ `).all(memoryId).map(rowToEvent);
144508
+ }
144509
+ markAccess(ids, at = (/* @__PURE__ */ new Date()).toISOString()) {
144510
+ const unique2 = [...new Set(ids.filter(Boolean))];
144511
+ if (unique2.length === 0) return;
144512
+ const statement = this.db.prepare(`
144513
+ UPDATE long_term_memories
144514
+ SET accessCount = accessCount + 1, lastAccessedAt = ?
144515
+ WHERE id = ?
144516
+ `);
144517
+ this.db.transaction(() => {
144518
+ for (const id of unique2) statement.run(at, id);
144519
+ })();
144520
+ }
144521
+ };
144522
+ }
144523
+ });
144524
+
144525
+ // src/memory/long-term-types.ts
144526
+ var LONG_TERM_MEMORY_KINDS, LONG_TERM_MEMORY_SCOPES, LONG_TERM_MEMORY_PORTABILITIES, LONG_TERM_MEMORY_EVIDENCE_KINDS, LONG_TERM_MEMORY_EVIDENCE_RELATIONS;
144527
+ var init_long_term_types = __esm({
144528
+ "src/memory/long-term-types.ts"() {
144529
+ "use strict";
144530
+ init_esm_shims();
144531
+ LONG_TERM_MEMORY_KINDS = ["episodic", "semantic", "procedural"];
144532
+ LONG_TERM_MEMORY_SCOPES = ["project", "user", "team"];
144533
+ LONG_TERM_MEMORY_PORTABILITIES = ["project-bound", "portable"];
144534
+ LONG_TERM_MEMORY_EVIDENCE_KINDS = [
144535
+ "observation",
144536
+ "claim",
144537
+ "workflow",
144538
+ "session",
144539
+ "checkpoint",
144540
+ "git",
144541
+ "code",
144542
+ "test",
144543
+ "run",
144544
+ "document",
144545
+ "manual",
144546
+ "user"
144547
+ ];
144548
+ LONG_TERM_MEMORY_EVIDENCE_RELATIONS = [
144549
+ "supports",
144550
+ "verifies",
144551
+ "derives",
144552
+ "user-confirmed"
144553
+ ];
144554
+ }
144555
+ });
144556
+
144557
+ // src/memory/long-term.ts
144558
+ var long_term_exports = {};
144559
+ __export(long_term_exports, {
144560
+ approveLongTermMemory: () => approveLongTermMemory,
144561
+ archiveLongTermMemory: () => archiveLongTermMemory,
144562
+ canReadLongTermMemory: () => canReadLongTermMemory,
144563
+ createLongTermMemoryCandidate: () => createLongTermMemoryCandidate,
144564
+ createManualLongTermMemory: () => createManualLongTermMemory,
144565
+ getLongTermMemoryDetail: () => getLongTermMemoryDetail,
144566
+ isEligibleLongTermMemory: () => isEligibleLongTermMemory,
144567
+ listLongTermMemories: () => listLongTermMemories,
144568
+ maintainLongTermMemories: () => maintainLongTermMemories,
144569
+ maybeAutoQualifyLongTermMemory: () => maybeAutoQualifyLongTermMemory,
144570
+ promoteObservationToLongTermMemory: () => promoteObservationToLongTermMemory,
144571
+ qualifyLongTermMemory: () => qualifyLongTermMemory,
144572
+ renderLongTermMemorySummary: () => renderLongTermMemorySummary,
144573
+ selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
144574
+ supersedeLongTermMemory: () => supersedeLongTermMemory
144575
+ });
144576
+ import { randomUUID as randomUUID8 } from "crypto";
144577
+ function isOneOf(value, values) {
144578
+ return typeof value === "string" && values.includes(value);
144579
+ }
144580
+ function compactText(value, field, max = MAX_TEXT_LENGTH) {
144581
+ if (typeof value !== "string") throw new Error("Long-term memory " + field + " must be text.");
144582
+ const safe = sanitizeCredentials(value).replace(/\s+/g, " ").trim();
144583
+ if (!safe) throw new Error("Long-term memory " + field + " is required.");
144584
+ if (safe.length > max) throw new Error("Long-term memory " + field + " is too long.");
144585
+ return safe;
144586
+ }
144587
+ function compactList(values, field) {
144588
+ if (!values) return [];
144589
+ if (!Array.isArray(values)) throw new Error("Long-term memory " + field + " must be an array.");
144590
+ return [...new Set(values.filter((value) => typeof value === "string").map((value) => compactText(value, field, 500)))].slice(0, MAX_LIST_ITEMS);
144591
+ }
144592
+ function normalizeEvidence(input) {
144593
+ if (!Array.isArray(input) || input.length === 0) {
144594
+ throw new Error("A long-term memory requires at least one source evidence reference.");
144595
+ }
144596
+ return input.map((evidence) => {
144597
+ if (!evidence || !isOneOf(evidence.kind, LONG_TERM_MEMORY_EVIDENCE_KINDS)) {
144598
+ throw new Error("Long-term memory evidence kind is invalid.");
144599
+ }
144600
+ if (!isOneOf(evidence.relation, LONG_TERM_MEMORY_EVIDENCE_RELATIONS)) {
144601
+ throw new Error("Long-term memory evidence relation is invalid.");
144602
+ }
144603
+ return {
144604
+ kind: evidence.kind,
144605
+ referenceId: compactText(evidence.referenceId, "evidence reference", 1e3),
144606
+ relation: evidence.relation,
144607
+ ...evidence.locator ? { locator: compactText(evidence.locator, "evidence locator", 1e3) } : {},
144608
+ ...evidence.capturedHash ? { capturedHash: compactText(evidence.capturedHash, "evidence hash", 1e3) } : {}
144609
+ };
144610
+ });
144611
+ }
144612
+ function assertScope(scope) {
144613
+ if (!isOneOf(scope, LONG_TERM_MEMORY_SCOPES)) throw new Error("Long-term memory scope is invalid.");
144614
+ }
144615
+ function assertKind(kind) {
144616
+ if (!isOneOf(kind, LONG_TERM_MEMORY_KINDS)) throw new Error("Long-term memory kind is invalid.");
144617
+ }
144618
+ function assertPortability(value) {
144619
+ if (!isOneOf(value, LONG_TERM_MEMORY_PORTABILITIES)) {
144620
+ throw new Error("Long-term memory portability is invalid.");
144621
+ }
144622
+ }
144623
+ function assertPortableEvidence(scope, portability, evidence) {
144624
+ if (portability !== "portable") return;
144625
+ if (scope !== "user") {
144626
+ throw new Error("Only user-scoped long-term memories may be portable across projects.");
144627
+ }
144628
+ if (evidence.some((item) => !PORTABLE_EVIDENCE_KINDS.has(item.kind))) {
144629
+ 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.");
144630
+ }
144631
+ }
144632
+ function requireTeamReader(scope, reader) {
144633
+ if (scope === "team" && reader?.isTeamMember !== true) {
144634
+ throw new Error("Team long-term memory requires an explicit active team identity for this project.");
144635
+ }
144636
+ }
144637
+ function matchesScope(memory, reader) {
144638
+ if (memory.scope === "project") return memory.originProjectId === reader.projectId;
144639
+ if (memory.scope === "team") {
144640
+ return memory.originProjectId === reader.projectId && reader.isTeamMember === true;
144641
+ }
144642
+ if (!reader.ownerId || memory.ownerId !== reader.ownerId) return false;
144643
+ return memory.portability === "portable" || memory.originProjectId === reader.projectId;
144644
+ }
144645
+ function canReadLongTermMemory(memory, reader) {
144646
+ return matchesScope(memory, reader);
144647
+ }
144648
+ function isEligibleLongTermMemory(memory) {
144649
+ return memory.state === "qualified" || memory.state === "approved";
144650
+ }
144651
+ function taskTerms(task) {
144652
+ const matches = task.toLocaleLowerCase("en-US").match(/[\p{L}\p{N}_./:-]+/gu) ?? [];
144653
+ return [...new Set(matches.filter((term) => term.length > 1 && !STOP_TERMS.has(term)))].slice(0, 16);
144654
+ }
144655
+ function kindFitScore(kind, task) {
144656
+ const normalized = task.toLocaleLowerCase("en-US");
144657
+ const hints = {
144658
+ episodic: ["resume", "continue", "handoff", "previous", "session", "\u63A5\u624B", "\u7EE7\u7EED", "\u4EA4\u63A5", "\u4E0A\u6B21", "\u4F1A\u8BDD"],
144659
+ semantic: ["why", "what", "architecture", "design", "decision", "reason", "\u4E3A\u4EC0\u4E48", "\u662F\u4EC0\u4E48", "\u67B6\u6784", "\u8BBE\u8BA1", "\u51B3\u7B56", "\u539F\u56E0"],
144660
+ procedural: ["how", "steps", "procedure", "run", "release", "publish", "verify", "implement", "\u6D41\u7A0B", "\u6B65\u9AA4", "\u53D1\u5E03", "\u9A8C\u8BC1", "\u4FEE\u590D", "\u5B9E\u73B0"]
144661
+ };
144662
+ return hints[kind].some((hint) => normalized.includes(hint)) ? 1 : 0;
144663
+ }
144664
+ function validationFreshnessScore(memory) {
144665
+ const validatedAt = memory.lastValidatedAt ?? memory.approvedAt ?? memory.qualifiedAt;
144666
+ if (!validatedAt) return 0;
144667
+ const time = Date.parse(validatedAt);
144668
+ if (!Number.isFinite(time)) return 0;
144669
+ const ageDays = Math.max(0, Date.now() - time) / (24 * 60 * 60 * 1e3);
144670
+ if (ageDays <= 30) return 0.35;
144671
+ if (ageDays <= 90) return 0.15;
144672
+ return 0;
144673
+ }
144674
+ function scoreForTask(memory, task) {
144675
+ const terms = taskTerms(task);
144676
+ if (terms.length === 0) return void 0;
144677
+ const title = memory.title.toLocaleLowerCase("en-US");
144678
+ const content = memory.content.toLocaleLowerCase("en-US");
144679
+ const facts = memory.facts.join(" ").toLocaleLowerCase("en-US");
144680
+ const tags = memory.tags.join(" ").toLocaleLowerCase("en-US");
144681
+ const applicability = (memory.applicability ?? "").toLocaleLowerCase("en-US");
144682
+ let score = memory.state === "approved" ? 0.5 : 0;
144683
+ const matched = [];
144684
+ for (const term of terms) {
144685
+ let termScore = 0;
144686
+ if (title.includes(term)) termScore += 5;
144687
+ if (tags.includes(term)) termScore += 4;
144688
+ if (applicability.includes(term)) termScore += 3;
144689
+ if (facts.includes(term)) termScore += 2;
144690
+ if (content.includes(term)) termScore += 1;
144691
+ if (termScore > 0) {
144692
+ score += termScore;
144693
+ matched.push(term);
144694
+ }
144695
+ }
144696
+ if (matched.length === 0) return void 0;
144697
+ score += kindFitScore(memory.kind, task);
144698
+ score += validationFreshnessScore(memory);
144699
+ const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
144700
+ const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
144701
+ return { score, reason: kindLabel + " matches " + matched.slice(0, 3).join(", ") + freshness };
144702
+ }
144703
+ function semanticText(memory) {
144704
+ return sanitizeCredentials([
144705
+ memory.title,
144706
+ memory.applicability,
144707
+ memory.tags.join(" "),
144708
+ memory.facts.join(" "),
144709
+ memory.content
144710
+ ].filter((value) => Boolean(value)).join("\n")).replace(/\s+/g, " ").trim().slice(0, MAX_TEXT_LENGTH);
144711
+ }
144712
+ function cosineSimilarity(left, right) {
144713
+ if (left.length === 0 || left.length !== right.length) return 0;
144714
+ let dot = 0;
144715
+ let leftMagnitude = 0;
144716
+ let rightMagnitude = 0;
144717
+ for (let index = 0; index < left.length; index += 1) {
144718
+ const a = left[index];
144719
+ const b = right[index];
144720
+ if (!Number.isFinite(a) || !Number.isFinite(b)) return 0;
144721
+ dot += a * b;
144722
+ leftMagnitude += a * a;
144723
+ rightMagnitude += b * b;
144724
+ }
144725
+ if (leftMagnitude === 0 || rightMagnitude === 0) return 0;
144726
+ return dot / Math.sqrt(leftMagnitude * rightMagnitude);
144727
+ }
144728
+ function semanticSelection(memory, similarity, task) {
144729
+ if (similarity < MIN_SEMANTIC_SIMILARITY) return void 0;
144730
+ const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
144731
+ const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
144732
+ return {
144733
+ score: similarity * 10 + (memory.state === "approved" ? 0.5 : 0) + kindFitScore(memory.kind, task) + validationFreshnessScore(memory),
144734
+ reason: kindLabel + " semantic match " + similarity.toFixed(2) + freshness
144735
+ };
144736
+ }
144737
+ async function resolveSemanticProvider(explicit) {
144738
+ if (explicit !== void 0) return explicit;
144739
+ try {
144740
+ const { getEmbeddingProvider: getEmbeddingProvider2 } = await Promise.resolve().then(() => (init_provider(), provider_exports));
144741
+ return await withTimeout(
144742
+ getEmbeddingProvider2({ requestTimeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS, retry: false }),
144743
+ SEMANTIC_RETRIEVAL_TIMEOUT_MS,
144744
+ "Long-term semantic provider initialization"
144745
+ );
144746
+ } catch {
144747
+ return null;
144748
+ }
144749
+ }
144750
+ function createStore(dataDir) {
144751
+ const store = new LongTermMemoryStore();
144752
+ return store.init(dataDir).then(() => store);
144753
+ }
144754
+ async function createManualLongTermMemory(input) {
144755
+ const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
144756
+ if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
144757
+ assertScope(input.scope);
144758
+ const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID8(), relation: "supports" }];
144759
+ return createLongTermMemoryWithDataDir({
144760
+ dataDir: input.dataDir,
144761
+ originProjectId: input.projectId,
144762
+ ownerId: owner.id,
144763
+ scope: input.scope,
144764
+ kind: input.kind,
144765
+ portability: input.portability,
144766
+ title: input.title,
144767
+ content: input.content,
144768
+ facts: input.facts,
144769
+ tags: input.tags,
144770
+ applicability: input.applicability,
144771
+ origin: "manual",
144772
+ evidence,
144773
+ reader: input.reader
144774
+ });
144775
+ }
144776
+ async function promoteObservationToLongTermMemory(input) {
144777
+ const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
144778
+ if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
144779
+ return createLongTermMemoryWithDataDir({
144780
+ dataDir: input.dataDir,
144781
+ originProjectId: input.observation.projectId,
144782
+ ownerId: owner.id,
144783
+ scope: input.scope,
144784
+ kind: input.kind,
144785
+ portability: "project-bound",
144786
+ title: input.observation.title,
144787
+ content: input.observation.narrative,
144788
+ facts: input.observation.facts,
144789
+ tags: input.tags ?? input.observation.concepts,
144790
+ applicability: input.applicability,
144791
+ origin: input.observation.source === "git" ? "git" : "agent",
144792
+ evidence: [{
144793
+ kind: "observation",
144794
+ referenceId: "obs:" + input.observation.projectId + ":" + input.observation.id,
144795
+ relation: "derives"
144796
+ }],
144797
+ reader: input.reader
144798
+ });
144799
+ }
144800
+ async function createLongTermMemoryCandidate(input) {
144801
+ return createLongTermMemoryWithDataDir(input);
144802
+ }
144803
+ async function createLongTermMemoryWithDataDir(input) {
144804
+ assertScope(input.scope);
144805
+ assertKind(input.kind);
144806
+ const portability = input.portability ?? "project-bound";
144807
+ assertPortability(portability);
144808
+ requireTeamReader(input.scope, input.reader);
144809
+ const evidenceInputs = normalizeEvidence(input.evidence);
144810
+ assertPortableEvidence(input.scope, portability, evidenceInputs);
144811
+ const now3 = (/* @__PURE__ */ new Date()).toISOString();
144812
+ const memory = {
144813
+ id: randomUUID8(),
144814
+ originProjectId: compactText(input.originProjectId, "origin project id", 1e3),
144815
+ ownerId: compactText(input.ownerId, "owner id", 160),
144816
+ scope: input.scope,
144817
+ kind: input.kind,
144818
+ state: "candidate",
144819
+ portability,
144820
+ title: compactText(input.title, "title", 500),
144821
+ content: compactText(input.content, "content"),
144822
+ facts: compactList(input.facts, "facts"),
144823
+ tags: compactList(input.tags, "tags"),
144824
+ ...input.applicability ? { applicability: compactText(input.applicability, "applicability", 1e3) } : {},
144825
+ origin: input.origin ?? "manual",
144826
+ createdAt: now3,
144827
+ updatedAt: now3,
144828
+ accessCount: 0
144829
+ };
144830
+ const store = await createStore(input.dataDir);
144831
+ const evidence = store.transaction(() => {
144832
+ store.insert(memory);
144833
+ const written = evidenceInputs.map((item) => store.insertEvidence({ memoryId: memory.id, ...item, createdAt: now3 }));
144834
+ store.recordEvent({
144835
+ memoryId: memory.id,
144836
+ kind: "created",
144837
+ toState: "candidate",
144838
+ detail: "Created as a source-backed long-term memory candidate.",
144839
+ createdAt: now3
144840
+ });
144841
+ return written;
144842
+ });
144843
+ return { memory, evidence };
144844
+ }
144845
+ function transitionDetail(value) {
144846
+ return compactText(value, "transition reason", 1e3);
144847
+ }
144848
+ async function transitionMemory(input) {
144849
+ const store = await createStore(input.dataDir);
144850
+ return store.transaction(() => {
144851
+ const current = store.get(input.id);
144852
+ if (!current) throw new Error("Long-term memory was not found.");
144853
+ if (current.state !== input.expected) {
144854
+ throw new Error("Long-term memory must be " + input.expected + " before it can be " + input.next + ".");
144855
+ }
144856
+ const evidence = store.listEvidence(current.id);
144857
+ if (evidence.length === 0) throw new Error("Long-term memory cannot advance without source evidence.");
144858
+ const now3 = (/* @__PURE__ */ new Date()).toISOString();
144859
+ const next = {
144860
+ ...current,
144861
+ state: input.next,
144862
+ updatedAt: now3,
144863
+ lastValidatedAt: now3,
144864
+ ...input.next === "qualified" ? { qualifiedAt: now3 } : { approvedAt: now3 }
144865
+ };
144866
+ store.update(next);
144867
+ store.recordEvent({
144868
+ memoryId: next.id,
144869
+ kind: input.event,
144870
+ fromState: current.state,
144871
+ toState: next.state,
144872
+ detail: transitionDetail(input.reason),
144873
+ createdAt: now3
144874
+ });
144875
+ return next;
144876
+ });
144877
+ }
144878
+ async function qualifyLongTermMemory(input) {
144879
+ return transitionMemory({ ...input, expected: "candidate", next: "qualified", event: "qualified" });
144880
+ }
144881
+ async function approveLongTermMemory(input) {
144882
+ return transitionMemory({ ...input, expected: "qualified", next: "approved", event: "approved" });
144883
+ }
144884
+ async function archiveLongTermMemory(input) {
144885
+ const store = await createStore(input.dataDir);
144886
+ return store.transaction(() => {
144887
+ const current = store.get(input.id);
144888
+ if (!current) throw new Error("Long-term memory was not found.");
144889
+ if (current.state === "archived" || current.state === "superseded") {
144890
+ throw new Error("Long-term memory is already inactive.");
144891
+ }
144892
+ const now3 = (/* @__PURE__ */ new Date()).toISOString();
144893
+ const next = { ...current, state: "archived", archivedAt: now3, updatedAt: now3 };
144894
+ store.update(next);
144895
+ store.recordEvent({
144896
+ memoryId: next.id,
144897
+ kind: "archived",
144898
+ fromState: current.state,
144899
+ toState: "archived",
144900
+ detail: transitionDetail(input.reason),
144901
+ createdAt: now3
144902
+ });
144903
+ return next;
144904
+ });
144905
+ }
144906
+ async function supersedeLongTermMemory(input) {
144907
+ const store = await createStore(input.dataDir);
144908
+ return store.transaction(() => {
144909
+ const current = store.get(input.id);
144910
+ if (!current) throw new Error("Long-term memory was not found.");
144911
+ if (current.state === "archived" || current.state === "superseded") {
144912
+ throw new Error("Long-term memory is already inactive.");
144913
+ }
144914
+ if (current.id === input.supersededBy) {
144915
+ throw new Error("Long-term memory cannot supersede itself.");
144916
+ }
144917
+ const replacement = store.get(input.supersededBy);
144918
+ if (!replacement || !isEligibleLongTermMemory(replacement)) {
144919
+ throw new Error("Replacement long-term memory must be qualified or approved.");
144920
+ }
144921
+ if (replacement.scope !== current.scope) {
144922
+ throw new Error("Replacement long-term memory must use the same scope.");
144923
+ }
144924
+ if (current.scope === "user" && replacement.ownerId !== current.ownerId) {
144925
+ throw new Error("User long-term memory may only be superseded by the same local owner.");
144926
+ }
144927
+ if (current.scope !== "user" && replacement.originProjectId !== current.originProjectId) {
144928
+ throw new Error("Project and team long-term memory may only be superseded within the same project.");
144929
+ }
144930
+ const now3 = (/* @__PURE__ */ new Date()).toISOString();
144931
+ const next = {
144932
+ ...current,
144933
+ state: "superseded",
144934
+ supersededBy: replacement.id,
144935
+ updatedAt: now3
144936
+ };
144937
+ store.update(next);
144938
+ store.recordEvent({
144939
+ memoryId: next.id,
144940
+ kind: "superseded",
144941
+ fromState: current.state,
144942
+ toState: "superseded",
144943
+ detail: transitionDetail(input.reason),
144944
+ createdAt: now3
144945
+ });
144946
+ return next;
144947
+ });
144948
+ }
144949
+ async function maybeAutoQualifyLongTermMemory(input) {
144950
+ if (input.source !== "manual" && input.sourceDetail !== "explicit") return null;
144951
+ try {
144952
+ return await qualifyLongTermMemory({
144953
+ dataDir: input.dataDir,
144954
+ id: input.id,
144955
+ reason: "auto-qualified: explicit request carries its own source evidence"
144956
+ });
144957
+ } catch {
144958
+ return null;
144959
+ }
144960
+ }
144961
+ async function maintainLongTermMemories(input) {
144962
+ const now3 = input.now ?? /* @__PURE__ */ new Date();
144963
+ const decayDays = input.decayDays ?? 30;
144964
+ const cutoff = now3.getTime() - decayDays * 24 * 60 * 60 * 1e3;
144965
+ const result = { archived: 0, superseded: 0 };
144966
+ const store = await createStore(input.dataDir);
144967
+ const all = store.list({ originProjectId: input.projectId });
144968
+ for (const memory of all) {
144969
+ if (memory.state !== "qualified" && memory.state !== "approved") continue;
144970
+ const lastActivity = Date.parse(memory.lastAccessedAt ?? memory.updatedAt);
144971
+ if (!Number.isFinite(lastActivity) || lastActivity >= cutoff) continue;
144972
+ try {
144973
+ await archiveLongTermMemory({
144974
+ dataDir: input.dataDir,
144975
+ id: memory.id,
144976
+ reason: "auto-archive: no activity since " + new Date(lastActivity).toISOString().slice(0, 10)
144977
+ });
144978
+ result.archived += 1;
144979
+ } catch {
144980
+ }
144981
+ }
144982
+ const groups = /* @__PURE__ */ new Map();
144983
+ for (const memory of store.list({ originProjectId: input.projectId })) {
144984
+ if (memory.state !== "qualified" && memory.state !== "approved") continue;
144985
+ const key = memory.scope + "\0" + memory.kind + "\0" + memory.title.trim().toLowerCase();
144986
+ const group = groups.get(key) ?? [];
144987
+ group.push(memory);
144988
+ groups.set(key, group);
144989
+ }
144990
+ for (const group of groups.values()) {
144991
+ if (group.length < 2) continue;
144992
+ group.sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt));
144993
+ const newest = group[0];
144994
+ for (const older of group.slice(1)) {
144995
+ try {
144996
+ await supersedeLongTermMemory({
144997
+ dataDir: input.dataDir,
144998
+ id: older.id,
144999
+ supersededBy: newest.id,
145000
+ reason: "auto-supersede: a newer record shares the same title"
145001
+ });
145002
+ result.superseded += 1;
145003
+ } catch {
145004
+ }
145005
+ }
145006
+ }
145007
+ return result;
145008
+ }
145009
+ async function listLongTermMemories(input) {
145010
+ const store = await createStore(input.dataDir);
145011
+ return store.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: store.listEvidence(memory.id) }));
145012
+ }
145013
+ async function getLongTermMemoryDetail(input) {
145014
+ const store = await createStore(input.dataDir);
145015
+ const memory = store.get(input.id);
145016
+ if (!memory || !canReadLongTermMemory(memory, input.reader)) {
145017
+ throw new Error("Long-term memory was not found in the active scope.");
145018
+ }
145019
+ store.markAccess([memory.id]);
145020
+ return { memory, evidence: store.listEvidence(memory.id), events: store.listEvents(memory.id) };
145021
+ }
145022
+ async function selectLongTermMemoriesForTask(input) {
145023
+ const task = input.task?.trim();
145024
+ if (!task) return [];
145025
+ const owner = await resolveLocalMemoryOwner(input.dataDir, { create: false });
145026
+ const reader = {
145027
+ projectId: input.projectId,
145028
+ ...owner ? { ownerId: owner.id } : {},
145029
+ ...input.agentId ? { agentId: input.agentId } : {},
145030
+ ...input.isTeamMember ? { isTeamMember: true } : {}
145031
+ };
145032
+ const store = await createStore(input.dataDir);
145033
+ const eligible = store.list({ limit: 1e3 }).filter((memory) => isEligibleLongTermMemory(memory) && canReadLongTermMemory(memory, reader));
145034
+ let selected = eligible.map((memory) => {
145035
+ const ranked = scoreForTask(memory, task);
145036
+ return ranked ? {
145037
+ memory,
145038
+ evidence: store.listEvidence(memory.id),
145039
+ score: ranked.score,
145040
+ reason: ranked.reason
145041
+ } : void 0;
145042
+ }).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));
145043
+ if (selected.length === 0 && eligible.length > 0) {
145044
+ const provider2 = await resolveSemanticProvider(input.embeddingProvider);
145045
+ const candidates = eligible.slice(0, MAX_SEMANTIC_CANDIDATES);
145046
+ if (provider2 && candidates.length > 0) {
145047
+ try {
145048
+ const vectors = await withTimeout(
145049
+ provider2.embedBatch([task, ...candidates.map(semanticText)], {
145050
+ timeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS,
145051
+ retry: false
145052
+ }),
145053
+ SEMANTIC_RETRIEVAL_TIMEOUT_MS,
145054
+ "Long-term semantic retrieval"
145055
+ );
145056
+ const query = vectors[0];
145057
+ if (Array.isArray(query)) {
145058
+ selected = candidates.map((memory, index) => {
145059
+ const vector = vectors[index + 1];
145060
+ const ranked = Array.isArray(vector) ? semanticSelection(memory, cosineSimilarity(query, vector), task) : void 0;
145061
+ return ranked ? {
145062
+ memory,
145063
+ evidence: store.listEvidence(memory.id),
145064
+ score: ranked.score,
145065
+ reason: ranked.reason
145066
+ } : void 0;
145067
+ }).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));
145068
+ }
145069
+ } catch {
145070
+ }
145071
+ }
145072
+ }
145073
+ selected = selected.slice(0, Math.max(1, Math.min(input.limit ?? 3, 5)));
145074
+ store.markAccess(selected.map((item) => item.memory.id));
145075
+ return selected;
145076
+ }
145077
+ function renderLongTermMemorySummary(memory, maxTokens = 22) {
145078
+ const source = [memory.title, memory.applicability, memory.content].filter(Boolean).join(": ");
145079
+ const safe = sanitizeCredentials(source).replace(/\s+/g, " ").trim();
145080
+ return countTextTokens(safe) <= maxTokens ? safe : truncateToTokenBudget(safe, maxTokens);
145081
+ }
145082
+ var MAX_TEXT_LENGTH, MAX_LIST_ITEMS, MAX_SEMANTIC_CANDIDATES, SEMANTIC_RETRIEVAL_TIMEOUT_MS, MIN_SEMANTIC_SIMILARITY, PORTABLE_EVIDENCE_KINDS, STOP_TERMS;
145083
+ var init_long_term = __esm({
145084
+ "src/memory/long-term.ts"() {
145085
+ "use strict";
145086
+ init_esm_shims();
145087
+ init_token_budget();
145088
+ init_timeout();
145089
+ init_secret_filter();
145090
+ init_owner();
145091
+ init_long_term_store();
145092
+ init_long_term_types();
145093
+ MAX_TEXT_LENGTH = 12e3;
145094
+ MAX_LIST_ITEMS = 40;
145095
+ MAX_SEMANTIC_CANDIDATES = 48;
145096
+ SEMANTIC_RETRIEVAL_TIMEOUT_MS = 1800;
145097
+ MIN_SEMANTIC_SIMILARITY = 0.58;
145098
+ PORTABLE_EVIDENCE_KINDS = /* @__PURE__ */ new Set(["manual", "user"]);
145099
+ STOP_TERMS = /* @__PURE__ */ new Set([
145100
+ "the",
145101
+ "and",
145102
+ "for",
145103
+ "with",
145104
+ "from",
145105
+ "that",
145106
+ "this",
145107
+ "into",
145108
+ "when",
145109
+ "what",
145110
+ "\u5982\u4F55",
145111
+ "\u4EC0\u4E48",
145112
+ "\u8FD9\u4E2A",
145113
+ "\u90A3\u4E2A",
145114
+ "\u6211\u4EEC",
145115
+ "\u9879\u76EE",
145116
+ "\u8FDB\u884C",
145117
+ "\u9700\u8981",
145118
+ "\u7EE7\u7EED",
145119
+ "\u5904\u7406"
145120
+ ]);
145121
+ }
145122
+ });
145123
+
144227
145124
  // src/codegraph/ids.ts
144228
145125
  import { createHash as createHash5 } from "crypto";
144229
145126
  function digest(input) {
@@ -144262,7 +145159,7 @@ var store_exports = {};
144262
145159
  __export(store_exports, {
144263
145160
  CodeGraphStore: () => CodeGraphStore
144264
145161
  });
144265
- import { randomUUID as randomUUID6 } from "crypto";
145162
+ import { randomUUID as randomUUID9 } from "crypto";
144266
145163
  import { posix as pathPosix } from "path";
144267
145164
  function rowToFile(row) {
144268
145165
  return {
@@ -144979,7 +145876,7 @@ var init_store = __esm({
144979
145876
  * so an interrupted scan cannot be advertised as complete.
144980
145877
  */
144981
145878
  recordCodeStateSnapshot(input) {
144982
- const id = randomUUID6();
145879
+ const id = randomUUID9();
144983
145880
  let snapshot;
144984
145881
  const tx = this.db.transaction(() => {
144985
145882
  const previous = this.db.prepare(
@@ -145757,8 +146654,8 @@ var claim_store_exports = {};
145757
146654
  __export(claim_store_exports, {
145758
146655
  ClaimStore: () => ClaimStore
145759
146656
  });
145760
- import { createHash as createHash8, randomUUID as randomUUID7 } from "crypto";
145761
- function optionalText2(value) {
146657
+ import { createHash as createHash8, randomUUID as randomUUID10 } from "crypto";
146658
+ function optionalText3(value) {
145762
146659
  return typeof value === "string" && value ? value : void 0;
145763
146660
  }
145764
146661
  function rowToClaim(row) {
@@ -145774,38 +146671,38 @@ function rowToClaim(row) {
145774
146671
  status: row.status,
145775
146672
  confidence: Number(row.confidence),
145776
146673
  observedAt: row.observedAt,
145777
- ...optionalText2(row.validFrom) ? { validFrom: row.validFrom } : {},
145778
- ...optionalText2(row.validTo) ? { validTo: row.validTo } : {},
145779
- ...optionalText2(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
146674
+ ...optionalText3(row.validFrom) ? { validFrom: row.validFrom } : {},
146675
+ ...optionalText3(row.validTo) ? { validTo: row.validTo } : {},
146676
+ ...optionalText3(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
145780
146677
  reviewState: row.reviewState,
145781
146678
  origin: row.origin,
145782
146679
  createdAt: row.createdAt,
145783
146680
  updatedAt: row.updatedAt
145784
146681
  };
145785
146682
  }
145786
- function rowToEvidence(row) {
146683
+ function rowToEvidence2(row) {
145787
146684
  return {
145788
146685
  id: row.id,
145789
146686
  claimId: row.claimId,
145790
146687
  evidenceKind: row.evidenceKind,
145791
146688
  evidenceId: row.evidenceId,
145792
146689
  relation: row.relation,
145793
- ...optionalText2(row.snapshotId) ? { snapshotId: row.snapshotId } : {},
145794
- ...optionalText2(row.locator) ? { locator: row.locator } : {},
145795
- ...optionalText2(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
146690
+ ...optionalText3(row.snapshotId) ? { snapshotId: row.snapshotId } : {},
146691
+ ...optionalText3(row.locator) ? { locator: row.locator } : {},
146692
+ ...optionalText3(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
145796
146693
  createdAt: row.createdAt
145797
146694
  };
145798
146695
  }
145799
- function rowToEvent(row) {
146696
+ function rowToEvent2(row) {
145800
146697
  return {
145801
146698
  id: row.id,
145802
146699
  projectId: row.projectId,
145803
146700
  claimId: row.claimId,
145804
146701
  kind: row.kind,
145805
- ...optionalText2(row.fromStatus) ? { fromStatus: row.fromStatus } : {},
145806
- ...optionalText2(row.toStatus) ? { toStatus: row.toStatus } : {},
145807
- ...optionalText2(row.relatedClaimId) ? { relatedClaimId: row.relatedClaimId } : {},
145808
- ...optionalText2(row.detail) ? { detail: row.detail } : {},
146702
+ ...optionalText3(row.fromStatus) ? { fromStatus: row.fromStatus } : {},
146703
+ ...optionalText3(row.toStatus) ? { toStatus: row.toStatus } : {},
146704
+ ...optionalText3(row.relatedClaimId) ? { relatedClaimId: row.relatedClaimId } : {},
146705
+ ...optionalText3(row.detail) ? { detail: row.detail } : {},
145809
146706
  createdAt: row.createdAt
145810
146707
  };
145811
146708
  }
@@ -145941,7 +146838,7 @@ var init_claim_store = __esm({
145941
146838
  locator, capturedHash, evidenceKey, createdAt
145942
146839
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
145943
146840
  `).run(
145944
- randomUUID7(),
146841
+ randomUUID10(),
145945
146842
  input.claimId,
145946
146843
  input.evidenceKind,
145947
146844
  input.evidenceId,
@@ -145959,11 +146856,11 @@ var init_claim_store = __esm({
145959
146856
  SELECT * FROM knowledge_claim_evidence
145960
146857
  WHERE claimId = ?
145961
146858
  ORDER BY createdAt ASC, id
145962
- `).all(claimId).map(rowToEvidence);
146859
+ `).all(claimId).map(rowToEvidence2);
145963
146860
  }
145964
146861
  recordEvent(input) {
145965
146862
  const event = {
145966
- id: randomUUID7(),
146863
+ id: randomUUID10(),
145967
146864
  ...input,
145968
146865
  ...input.detail ? { detail: sanitizeCredentials(input.detail) } : {},
145969
146866
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
@@ -145991,7 +146888,7 @@ var init_claim_store = __esm({
145991
146888
  SELECT * FROM knowledge_claim_events
145992
146889
  WHERE claimId = ?
145993
146890
  ORDER BY createdAt ASC, id
145994
- `).all(claimId).map(rowToEvent);
146891
+ `).all(claimId).map(rowToEvent2);
145995
146892
  }
145996
146893
  };
145997
146894
  }
@@ -146008,8 +146905,8 @@ __export(claims_exports, {
146008
146905
  supersedeClaim: () => supersedeClaim,
146009
146906
  writeClaim: () => writeClaim
146010
146907
  });
146011
- import { createHash as createHash9, randomUUID as randomUUID8 } from "crypto";
146012
- function compactText(value, field) {
146908
+ import { createHash as createHash9, randomUUID as randomUUID11 } from "crypto";
146909
+ function compactText2(value, field) {
146013
146910
  if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
146014
146911
  const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
146015
146912
  if (!sanitized) throw new Error("Claim " + field + " is required");
@@ -146017,7 +146914,7 @@ function compactText(value, field) {
146017
146914
  return sanitized;
146018
146915
  }
146019
146916
  function normalizedTerm(value) {
146020
- return compactText(value, "identity").toLocaleLowerCase("en-US");
146917
+ return compactText2(value, "identity").toLocaleLowerCase("en-US");
146021
146918
  }
146022
146919
  function hashIdentity(parts) {
146023
146920
  return createHash9("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
@@ -146046,7 +146943,7 @@ function validateEvidence(input) {
146046
146943
  if (!evidence || typeof evidence !== "object") {
146047
146944
  throw new Error("Claim evidence must be an object");
146048
146945
  }
146049
- const evidenceId = compactText(evidence.evidenceId, "evidence id");
146946
+ const evidenceId = compactText2(evidence.evidenceId, "evidence id");
146050
146947
  if (evidenceId.length > MAX_EVIDENCE_ID_LENGTH) {
146051
146948
  throw new Error("Claim evidence id is too long");
146052
146949
  }
@@ -146060,9 +146957,9 @@ function validateEvidence(input) {
146060
146957
  evidenceKind: evidence.evidenceKind,
146061
146958
  evidenceId,
146062
146959
  relation: evidence.relation,
146063
- ...evidence.snapshotId ? { snapshotId: compactText(evidence.snapshotId, "evidence snapshot id") } : {},
146064
- ...evidence.locator ? { locator: compactText(evidence.locator, "evidence locator") } : {},
146065
- ...evidence.capturedHash ? { capturedHash: compactText(evidence.capturedHash, "evidence hash") } : {}
146960
+ ...evidence.snapshotId ? { snapshotId: compactText2(evidence.snapshotId, "evidence snapshot id") } : {},
146961
+ ...evidence.locator ? { locator: compactText2(evidence.locator, "evidence locator") } : {},
146962
+ ...evidence.capturedHash ? { capturedHash: compactText2(evidence.capturedHash, "evidence hash") } : {}
146066
146963
  };
146067
146964
  });
146068
146965
  }
@@ -146070,10 +146967,10 @@ function normalizeClaimInput(input) {
146070
146967
  if (!["project", "workspace", "team", "workflow", "task"].includes(input.scope)) {
146071
146968
  throw new Error("Claim scope is invalid");
146072
146969
  }
146073
- const projectId = compactText(input.projectId, "project id");
146074
- const subject = compactText(input.subject, "subject");
146075
- const predicate = compactText(input.predicate, "predicate");
146076
- const objectValue = compactText(input.objectValue, "object value");
146970
+ const projectId = compactText2(input.projectId, "project id");
146971
+ const subject = compactText2(input.subject, "subject");
146972
+ const predicate = compactText2(input.predicate, "predicate");
146973
+ const objectValue = compactText2(input.objectValue, "object value");
146077
146974
  const identity = buildClaimIdentity({ subject, predicate, objectValue, scope: input.scope });
146078
146975
  const origin = input.origin ?? "explicit";
146079
146976
  let reviewState = input.reviewState ?? "approved";
@@ -146094,7 +146991,7 @@ function normalizeClaimInput(input) {
146094
146991
  const now3 = (/* @__PURE__ */ new Date()).toISOString();
146095
146992
  return {
146096
146993
  claim: {
146097
- id: randomUUID8(),
146994
+ id: randomUUID11(),
146098
146995
  projectId,
146099
146996
  subject,
146100
146997
  predicate,
@@ -146194,7 +147091,7 @@ function reviewClaim(store, input) {
146194
147091
  if (input.reviewState !== "approved" && input.reviewState !== "rejected") {
146195
147092
  throw new Error("A claim review must approve or reject the claim");
146196
147093
  }
146197
- const detail = compactText(input.detail, "review detail");
147094
+ const detail = compactText2(input.detail, "review detail");
146198
147095
  return store.transaction(() => {
146199
147096
  const claim = store.getClaim(input.claimId);
146200
147097
  if (!claim) throw new Error("Claim was not found");
@@ -146506,8 +147403,8 @@ var init_frontmatter = __esm({
146506
147403
 
146507
147404
  // src/knowledge/markdown.ts
146508
147405
  import { createHash as createHash10 } from "crypto";
146509
- import { promises as fs12 } from "fs";
146510
- import path19 from "path";
147406
+ import { promises as fs13 } from "fs";
147407
+ import path20 from "path";
146511
147408
  function hashContent(content) {
146512
147409
  return createHash10("sha256").update(content).digest("hex");
146513
147410
  }
@@ -146565,8 +147462,8 @@ function extractInternalMarkdownLinks(body) {
146565
147462
  return [...links].sort();
146566
147463
  }
146567
147464
  function resolvePageLink(sourceRelativePath, target) {
146568
- const sourceDir = path19.posix.dirname(sourceRelativePath.replace(/\\/g, "/"));
146569
- const normalized = path19.posix.normalize(path19.posix.join(sourceDir, target.replace(/\\/g, "/")));
147465
+ const sourceDir = path20.posix.dirname(sourceRelativePath.replace(/\\/g, "/"));
147466
+ const normalized = path20.posix.normalize(path20.posix.join(sourceDir, target.replace(/\\/g, "/")));
146570
147467
  if (!normalized || normalized === "." || normalized === ".." || normalized.startsWith("../")) return void 0;
146571
147468
  return normalized;
146572
147469
  }
@@ -146588,13 +147485,13 @@ function renderKnowledgePage(frontmatter, body) {
146588
147485
  });
146589
147486
  }
146590
147487
  async function readKnowledgePage(absolutePath, workspaceRoot) {
146591
- const raw = await fs12.readFile(absolutePath, "utf8");
147488
+ const raw = await fs13.readFile(absolutePath, "utf8");
146592
147489
  try {
146593
147490
  const parsed = frontmatter_default(raw);
146594
147491
  const frontmatter = validateKnowledgePageFrontmatter(parsed.data);
146595
147492
  return {
146596
147493
  absolutePath,
146597
- relativePath: workspaceRoot ? path19.relative(workspaceRoot, absolutePath).split(path19.sep).join("/") : path19.basename(absolutePath),
147494
+ relativePath: workspaceRoot ? path20.relative(workspaceRoot, absolutePath).split(path20.sep).join("/") : path20.basename(absolutePath),
146598
147495
  frontmatter,
146599
147496
  body: parsed.content.trim(),
146600
147497
  contentHash: hashContent(raw),
@@ -146606,7 +147503,7 @@ async function readKnowledgePage(absolutePath, workspaceRoot) {
146606
147503
  }
146607
147504
  }
146608
147505
  async function writeKnowledgePage(absolutePath, content) {
146609
- await fs12.mkdir(path19.dirname(absolutePath), { recursive: true });
147506
+ await fs13.mkdir(path20.dirname(absolutePath), { recursive: true });
146610
147507
  await atomicWriteFile(absolutePath, content);
146611
147508
  return hashContent(content);
146612
147509
  }
@@ -146636,8 +147533,8 @@ __export(wiki_exports, {
146636
147533
  readKnowledgePage: () => readKnowledgePage
146637
147534
  });
146638
147535
  import { createHash as createHash11 } from "crypto";
146639
- import { promises as fs13 } from "fs";
146640
- import path20 from "path";
147536
+ import { promises as fs14 } from "fs";
147537
+ import path21 from "path";
146641
147538
  function hash2(value) {
146642
147539
  return createHash11("sha256").update(value).digest("hex");
146643
147540
  }
@@ -146769,7 +147666,7 @@ function candidatePage(workspace, title, claims, store) {
146769
147666
  }
146770
147667
  async function fileHashIfPresent(filePath) {
146771
147668
  try {
146772
- return pageContentHash(await fs13.readFile(filePath, "utf8"));
147669
+ return pageContentHash(await fs14.readFile(filePath, "utf8"));
146773
147670
  } catch (error) {
146774
147671
  const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
146775
147672
  if (code === "ENOENT") return void 0;
@@ -146793,8 +147690,8 @@ async function writeIndex(workspace, store) {
146793
147690
  lines.push("No pending proposals.");
146794
147691
  } else {
146795
147692
  for (const proposal of pending) {
146796
- const relative3 = path20.relative(paths.root, proposal.proposalPath).split(path20.sep).join("/");
146797
- lines.push("- [" + path20.basename(proposal.proposalPath, ".md") + "](" + relative3 + ")");
147693
+ const relative3 = path21.relative(paths.root, proposal.proposalPath).split(path21.sep).join("/");
147694
+ lines.push("- [" + path21.basename(proposal.proposalPath, ".md") + "](" + relative3 + ")");
146798
147695
  }
146799
147696
  }
146800
147697
  lines.push("");
@@ -146802,7 +147699,7 @@ async function writeIndex(workspace, store) {
146802
147699
  }
146803
147700
  async function appendLog(workspace, line) {
146804
147701
  const logPath = getKnowledgeWorkspacePaths(workspace).log;
146805
- await fs13.appendFile(logPath, "- " + now() + " " + line + "\n", "utf8");
147702
+ await fs14.appendFile(logPath, "- " + now() + " " + line + "\n", "utf8");
146806
147703
  }
146807
147704
  function toPageRecord(workspace, page, status, contentHash, manualContentHash) {
146808
147705
  return {
@@ -146887,9 +147784,9 @@ async function applyKnowledgeProposal(input) {
146887
147784
  }
146888
147785
  if (proposal.status !== "pending") throw new Error("Knowledge proposal is not pending review");
146889
147786
  const root = getKnowledgeWorkspacePaths(input.workspace).root;
146890
- const targetPath = path20.resolve(proposal.targetPath);
146891
- const proposalPath = path20.resolve(proposal.proposalPath);
146892
- if (!targetPath.startsWith(root + path20.sep) || !proposalPath.startsWith(root + path20.sep)) {
147787
+ const targetPath = path21.resolve(proposal.targetPath);
147788
+ const proposalPath = path21.resolve(proposal.proposalPath);
147789
+ if (!targetPath.startsWith(root + path21.sep) || !proposalPath.startsWith(root + path21.sep)) {
146893
147790
  throw new Error("Knowledge proposal path escapes its workspace");
146894
147791
  }
146895
147792
  await withFileLock(root, async () => {
@@ -146927,12 +147824,12 @@ async function markdownFiles(directory) {
146927
147824
  const files = [];
146928
147825
  let entries;
146929
147826
  try {
146930
- entries = await fs13.readdir(directory, { withFileTypes: true });
147827
+ entries = await fs14.readdir(directory, { withFileTypes: true });
146931
147828
  } catch {
146932
147829
  return files;
146933
147830
  }
146934
147831
  for (const entry of entries) {
146935
- const filePath = path20.join(directory, entry.name);
147832
+ const filePath = path21.join(directory, entry.name);
146936
147833
  if (entry.isDirectory()) {
146937
147834
  files.push(...await markdownFiles(filePath));
146938
147835
  } else if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
@@ -146955,13 +147852,13 @@ async function lintKnowledgeWorkspace(input) {
146955
147852
  kind: "malformed-frontmatter",
146956
147853
  severity: "error",
146957
147854
  message: error instanceof Error ? error.message : "Malformed knowledge page.",
146958
- relativePath: path20.relative(paths.root, filePath).split(path20.sep).join("/")
147855
+ relativePath: path21.relative(paths.root, filePath).split(path21.sep).join("/")
146959
147856
  });
146960
147857
  }
146961
147858
  }
146962
147859
  const indexed = /* @__PURE__ */ new Set();
146963
147860
  try {
146964
- const index = await fs13.readFile(paths.index, "utf8");
147861
+ const index = await fs14.readFile(paths.index, "utf8");
146965
147862
  for (const link of extractInternalMarkdownLinks(index)) {
146966
147863
  const resolved = resolvePageLink("index.md", link);
146967
147864
  if (resolved) indexed.add(resolved);
@@ -147050,7 +147947,7 @@ async function lintKnowledgeWorkspace(input) {
147050
147947
  kind: "manual-edit-protected",
147051
147948
  severity: "warning",
147052
147949
  message: "A newer proposal was held because the target page has manual edits.",
147053
- relativePath: path20.relative(paths.root, proposal.targetPath).split(path20.sep).join("/")
147950
+ relativePath: path21.relative(paths.root, proposal.targetPath).split(path21.sep).join("/")
147054
147951
  });
147055
147952
  }
147056
147953
  }
@@ -147183,7 +148080,7 @@ var workflow_store_exports = {};
147183
148080
  __export(workflow_store_exports, {
147184
148081
  WorkflowStore: () => WorkflowStore
147185
148082
  });
147186
- import { randomUUID as randomUUID9 } from "crypto";
148083
+ import { randomUUID as randomUUID12 } from "crypto";
147187
148084
  function parseJson(value, fallback) {
147188
148085
  if (typeof value !== "string" || !value) return fallback;
147189
148086
  try {
@@ -147192,7 +148089,7 @@ function parseJson(value, fallback) {
147192
148089
  return fallback;
147193
148090
  }
147194
148091
  }
147195
- function optionalText3(value) {
148092
+ function optionalText4(value) {
147196
148093
  return typeof value === "string" && value.trim() ? value : void 0;
147197
148094
  }
147198
148095
  function rowToWorkflow(row) {
@@ -147229,14 +148126,14 @@ function rowToRun(row) {
147229
148126
  workflowId: row.workflowId,
147230
148127
  projectId: row.projectId,
147231
148128
  task: row.task,
147232
- ...optionalText3(row.startingSnapshotId) ? { startingSnapshotId: row.startingSnapshotId } : {},
148129
+ ...optionalText4(row.startingSnapshotId) ? { startingSnapshotId: row.startingSnapshotId } : {},
147233
148130
  selectedEvidence: parseJson(row.selectedEvidenceJson, []),
147234
148131
  phaseState: parseJson(row.phaseStateJson, {}),
147235
148132
  outcome: row.outcome,
147236
148133
  verificationVerdict: row.verificationVerdict,
147237
- ...optionalText3(row.failureReason) ? { failureReason: row.failureReason } : {},
148134
+ ...optionalText4(row.failureReason) ? { failureReason: row.failureReason } : {},
147238
148135
  startedAt: row.startedAt,
147239
- ...optionalText3(row.completedAt) ? { completedAt: row.completedAt } : {}
148136
+ ...optionalText4(row.completedAt) ? { completedAt: row.completedAt } : {}
147240
148137
  };
147241
148138
  }
147242
148139
  var WorkflowStore;
@@ -147283,7 +148180,7 @@ var init_workflow_store = __esm({
147283
148180
  }
147284
148181
  recordRun(input) {
147285
148182
  const run = {
147286
- id: randomUUID9(),
148183
+ id: randomUUID12(),
147287
148184
  workflowId: input.workflowId,
147288
148185
  projectId: input.projectId,
147289
148186
  task: input.task.trim(),
@@ -147361,8 +148258,8 @@ var init_outcome_types = __esm({
147361
148258
  });
147362
148259
 
147363
148260
  // src/knowledge/outcome-store.ts
147364
- import { randomUUID as randomUUID10 } from "crypto";
147365
- function optionalText4(value) {
148261
+ import { randomUUID as randomUUID13 } from "crypto";
148262
+ function optionalText5(value) {
147366
148263
  return typeof value === "string" && value.trim() ? value : void 0;
147367
148264
  }
147368
148265
  function text(value, field, max = 1e3) {
@@ -147385,8 +148282,8 @@ function rowToSignal(row) {
147385
148282
  candidateId: row.candidateId,
147386
148283
  kind: row.kind,
147387
148284
  sourceRef: row.sourceRef,
147388
- ...optionalText4(row.snapshotId) ? { snapshotId: row.snapshotId } : {},
147389
- ...optionalText4(row.detail) ? { detail: row.detail } : {},
148285
+ ...optionalText5(row.snapshotId) ? { snapshotId: row.snapshotId } : {},
148286
+ ...optionalText5(row.detail) ? { detail: row.detail } : {},
147390
148287
  observedAt: row.observedAt
147391
148288
  };
147392
148289
  }
@@ -147405,7 +148302,7 @@ var init_outcome_store = __esm({
147405
148302
  }
147406
148303
  record(input) {
147407
148304
  const signal = {
147408
- id: randomUUID10(),
148305
+ id: randomUUID13(),
147409
148306
  projectId: text(input.projectId, "project id"),
147410
148307
  candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
147411
148308
  candidateId: text(input.candidateId, "candidate id"),
@@ -147832,8 +148729,8 @@ __export(workflows_exports, {
147832
148729
  writeCanonicalWorkflow: () => writeCanonicalWorkflow
147833
148730
  });
147834
148731
  import { createHash as createHash12 } from "crypto";
147835
- import { promises as fs14 } from "fs";
147836
- import path21 from "path";
148732
+ import { promises as fs15 } from "fs";
148733
+ import path22 from "path";
147837
148734
  function hash3(value) {
147838
148735
  return createHash12("sha256").update(value).digest("hex");
147839
148736
  }
@@ -147854,7 +148751,7 @@ function requiredText(data, key) {
147854
148751
  }
147855
148752
  return value.trim();
147856
148753
  }
147857
- function optionalText5(data, key) {
148754
+ function optionalText6(data, key) {
147858
148755
  const value = data[key];
147859
148756
  if (value === void 0 || value === null || value === "") return void 0;
147860
148757
  if (typeof value !== "string") throw new Error("workflow frontmatter field " + key + " must be text");
@@ -147897,11 +148794,11 @@ function phaseFromValue(value, index) {
147897
148794
  }
147898
148795
  const data = value;
147899
148796
  const title = requiredText(data, "title");
147900
- const phaseId = optionalText5(data, "id") ?? slug(title) + "-" + (index + 1);
148797
+ const phaseId = optionalText6(data, "id") ?? slug(title) + "-" + (index + 1);
147901
148798
  return {
147902
148799
  id: phaseId,
147903
148800
  title,
147904
- instructions: optionalText5(data, "instructions") ?? "",
148801
+ instructions: optionalText6(data, "instructions") ?? "",
147905
148802
  branches: optionalStringArray(data, "branches"),
147906
148803
  expectedOutputs: optionalStringArray(data, "expectedOutputs"),
147907
148804
  verificationGates: optionalStringArray(data, "verificationGates")
@@ -147936,7 +148833,7 @@ function phasesFromBody(body) {
147936
148833
  }
147937
148834
  function normalizeSourcePath(sourcePath) {
147938
148835
  const normalized = sourcePath.replace(/\\/g, "/");
147939
- if (!normalized.startsWith("workflows/") || !normalized.toLowerCase().endsWith(".md") || normalized.includes("../") || path21.posix.normalize(normalized) !== normalized) {
148836
+ if (!normalized.startsWith("workflows/") || !normalized.toLowerCase().endsWith(".md") || normalized.includes("../") || path22.posix.normalize(normalized) !== normalized) {
147940
148837
  throw new Error("workflow source path must be a safe workflows/*.md path");
147941
148838
  }
147942
148839
  return normalized;
@@ -148010,7 +148907,7 @@ function parsedWorkflow(data, body, input) {
148010
148907
  id: requiredText(data, "id"),
148011
148908
  workspaceId: input.workspaceId,
148012
148909
  title: requiredText(data, "title"),
148013
- description: optionalText5(data, "description") ?? "",
148910
+ description: optionalText6(data, "description") ?? "",
148014
148911
  status: optionalStatus(data),
148015
148912
  version: optionalNumber(data, "version", 1),
148016
148913
  taskLenses: optionalStringArray(data, "taskLenses"),
@@ -148029,9 +148926,9 @@ function parsedWorkflow(data, body, input) {
148029
148926
  sourcePath: normalizeSourcePath(input.sourcePath),
148030
148927
  sourceHash: "",
148031
148928
  contentHash: input.contentHash,
148032
- createdAt: optionalText5(data, "createdAt") ?? now2(),
148033
- updatedAt: optionalText5(data, "updatedAt") ?? now2(),
148034
- ...optionalText5(data, "importedFrom") ? { importedFrom: optionalText5(data, "importedFrom") } : {}
148929
+ createdAt: optionalText6(data, "createdAt") ?? now2(),
148930
+ updatedAt: optionalText6(data, "updatedAt") ?? now2(),
148931
+ ...optionalText6(data, "importedFrom") ? { importedFrom: optionalText6(data, "importedFrom") } : {}
148035
148932
  };
148036
148933
  if (candidate.phases.length === 0) {
148037
148934
  throw new Error("workflow must contain at least one phase or a non-empty body");
@@ -148085,7 +148982,7 @@ async function writeCanonicalWorkflow(input) {
148085
148982
  const filePath = resolveKnowledgeWorkspaceFile(input.workspace, workflow.sourcePath);
148086
148983
  const content = renderWorkflowMarkdown(workflow);
148087
148984
  await withFileLock(paths.root, async () => {
148088
- await fs14.mkdir(path21.dirname(filePath), { recursive: true });
148985
+ await fs15.mkdir(path22.dirname(filePath), { recursive: true });
148089
148986
  await atomicWriteFile(filePath, content);
148090
148987
  });
148091
148988
  const store = await storeFor2(input.workspace);
@@ -148094,13 +148991,13 @@ async function writeCanonicalWorkflow(input) {
148094
148991
  async function markdownFiles2(directory) {
148095
148992
  let entries;
148096
148993
  try {
148097
- entries = await fs14.readdir(directory, { withFileTypes: true });
148994
+ entries = await fs15.readdir(directory, { withFileTypes: true });
148098
148995
  } catch {
148099
148996
  return [];
148100
148997
  }
148101
148998
  const files = [];
148102
148999
  for (const entry of entries) {
148103
- const absolutePath = path21.join(directory, entry.name);
149000
+ const absolutePath = path22.join(directory, entry.name);
148104
149001
  if (entry.isDirectory()) {
148105
149002
  files.push(...await markdownFiles2(absolutePath));
148106
149003
  } else if (entry.isFile() && entry.name.toLowerCase().endsWith(".md")) {
@@ -148115,9 +149012,9 @@ async function syncCanonicalWorkflows(workspace) {
148115
149012
  const workflows = [];
148116
149013
  const errors = [];
148117
149014
  for (const absolutePath of await markdownFiles2(paths.workflows)) {
148118
- const sourcePath = path21.relative(paths.root, absolutePath).split(path21.sep).join("/");
149015
+ const sourcePath = path22.relative(paths.root, absolutePath).split(path22.sep).join("/");
148119
149016
  try {
148120
- const raw = await fs14.readFile(absolutePath, "utf8");
149017
+ const raw = await fs15.readFile(absolutePath, "utf8");
148121
149018
  const workflow = parseWorkflowMarkdown(raw, { workspaceId: workspace.id, sourcePath });
148122
149019
  workflows.push(store.upsertWorkflow(workflow));
148123
149020
  } catch (error) {
@@ -148229,21 +149126,21 @@ function importedWorkflowSpec(input) {
148229
149126
  return materializeWorkflow(spec);
148230
149127
  }
148231
149128
  async function importWindsurfWorkflows(input) {
148232
- const sourceDirectory = path21.join(path21.resolve(input.projectRoot), ".windsurf", "workflows");
149129
+ const sourceDirectory = path22.join(path22.resolve(input.projectRoot), ".windsurf", "workflows");
148233
149130
  const paths = getKnowledgeWorkspacePaths(input.workspace);
148234
149131
  const imported = [];
148235
149132
  const skipped = [];
148236
149133
  let entries;
148237
149134
  try {
148238
- entries = await fs14.readdir(sourceDirectory, { withFileTypes: true });
149135
+ entries = await fs15.readdir(sourceDirectory, { withFileTypes: true });
148239
149136
  } catch {
148240
149137
  return { imported, skipped };
148241
149138
  }
148242
149139
  for (const entry of entries.filter((item) => item.isFile() && item.name.toLowerCase().endsWith(".md"))) {
148243
- const originalPath = path21.join(sourceDirectory, entry.name);
148244
- const sourcePath = path21.relative(path21.resolve(input.projectRoot), originalPath).split(path21.sep).join("/");
149140
+ const originalPath = path22.join(sourceDirectory, entry.name);
149141
+ const sourcePath = path22.relative(path22.resolve(input.projectRoot), originalPath).split(path22.sep).join("/");
148245
149142
  try {
148246
- const raw = await fs14.readFile(originalPath, "utf8");
149143
+ const raw = await fs15.readFile(originalPath, "utf8");
148247
149144
  const workflow = importedWorkflowSpec({
148248
149145
  workspace: input.workspace,
148249
149146
  sourceName: entry.name,
@@ -148252,7 +149149,7 @@ async function importWindsurfWorkflows(input) {
148252
149149
  });
148253
149150
  const targetPath = resolveKnowledgeWorkspaceFile(input.workspace, workflow.sourcePath);
148254
149151
  try {
148255
- await fs14.access(targetPath);
149152
+ await fs15.access(targetPath);
148256
149153
  skipped.push({ sourcePath, reason: "canonical workflow already exists and was preserved" });
148257
149154
  continue;
148258
149155
  } catch {
@@ -148265,12 +149162,12 @@ async function importWindsurfWorkflows(input) {
148265
149162
  });
148266
149163
  }
148267
149164
  }
148268
- await fs14.mkdir(paths.workflows, { recursive: true });
149165
+ await fs15.mkdir(paths.workflows, { recursive: true });
148269
149166
  return { imported, skipped };
148270
149167
  }
148271
149168
  function isWithin2(root, candidate) {
148272
- const relative3 = path21.relative(root, candidate);
148273
- return relative3 !== "" && relative3 !== ".." && !relative3.startsWith(".." + path21.sep) && !path21.isAbsolute(relative3);
149169
+ const relative3 = path22.relative(root, candidate);
149170
+ return relative3 !== "" && relative3 !== ".." && !relative3.startsWith(".." + path22.sep) && !path22.isAbsolute(relative3);
148274
149171
  }
148275
149172
  function adapterRelativePath(workflow, agent) {
148276
149173
  const name = "memorix-workflow-" + slug(workflow.id.replace(/^workflow:/, ""));
@@ -148356,15 +149253,15 @@ async function previewWorkflowAdapter(input) {
148356
149253
  reason: "The canonical workflow does not declare compatibility with this agent."
148357
149254
  };
148358
149255
  }
148359
- const projectRoot = path21.resolve(input.projectRoot);
148360
- const targetPath = path21.resolve(projectRoot, adapterRelativePath(input.workflow, input.agent));
149256
+ const projectRoot = path22.resolve(input.projectRoot);
149257
+ const targetPath = path22.resolve(projectRoot, adapterRelativePath(input.workflow, input.agent));
148361
149258
  if (!isWithin2(projectRoot, targetPath)) {
148362
149259
  throw new Error("Workflow adapter target escapes the project root");
148363
149260
  }
148364
149261
  const content = adapterContent(input.workflow, input.agent);
148365
149262
  let existing;
148366
149263
  try {
148367
- existing = await fs14.readFile(targetPath, "utf8");
149264
+ existing = await fs15.readFile(targetPath, "utf8");
148368
149265
  } catch (error) {
148369
149266
  const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
148370
149267
  if (code !== "ENOENT") throw error;
@@ -148385,11 +149282,11 @@ async function applyWorkflowAdapter(input) {
148385
149282
  if (initial.status === "unsupported" || initial.status === "conflict" || initial.status === "unchanged") {
148386
149283
  return initial;
148387
149284
  }
148388
- const projectRoot = path21.resolve(input.projectRoot);
149285
+ const projectRoot = path22.resolve(input.projectRoot);
148389
149286
  return withFileLock(projectRoot, async () => {
148390
149287
  const current = await previewWorkflowAdapter(input);
148391
149288
  if (current.status !== "create" && current.status !== "update") return current;
148392
- await fs14.mkdir(path21.dirname(current.targetPath), { recursive: true });
149289
+ await fs15.mkdir(path22.dirname(current.targetPath), { recursive: true });
148393
149290
  await atomicWriteFile(current.targetPath, current.content);
148394
149291
  return current;
148395
149292
  });
@@ -148679,6 +149576,11 @@ function createProjectMaintenanceHandler(projectId, projectDir2, projectRoot, op
148679
149576
  }
148680
149577
  return { action: "complete" };
148681
149578
  }
149579
+ if (job.kind === "long-term-maintenance") {
149580
+ const { maintainLongTermMemories: maintainLongTermMemories2 } = await Promise.resolve().then(() => (init_long_term(), long_term_exports));
149581
+ await maintainLongTermMemories2({ dataDir: projectDir2, projectId });
149582
+ return { action: "reschedule", delayMs: 24 * 60 * 60 * 1e3, resetAttempts: true };
149583
+ }
148682
149584
  if (job.kind === "consolidation") {
148683
149585
  const limit2 = consolidationBatchSize(job.payload);
148684
149586
  const result2 = await runAutomaticConsolidation(projectId, projectDir2, {
@@ -149020,15 +149922,15 @@ __export(vector_backfill_runner_exports, {
149020
149922
  });
149021
149923
  import { spawn as spawn4 } from "child_process";
149022
149924
  import { existsSync as existsSync10 } from "fs";
149023
- import path22 from "path";
149925
+ import path23 from "path";
149024
149926
  import { fileURLToPath as fileURLToPath5 } from "url";
149025
149927
  function isNonEmptyString(value) {
149026
149928
  return typeof value === "string" && value.trim().length > 0;
149027
149929
  }
149028
149930
  function resolveVectorBackfillRunnerPath(moduleUrl = import.meta.url) {
149029
- const moduleDir = path22.dirname(fileURLToPath5(moduleUrl));
149030
- const distDir = path22.basename(moduleDir) === "cli" ? path22.dirname(moduleDir) : path22.basename(moduleDir) === "runtime" && path22.basename(path22.dirname(moduleDir)) === "src" ? path22.join(path22.dirname(path22.dirname(moduleDir)), "dist") : moduleDir;
149031
- return path22.join(distDir, "vector-backfill-runner.js");
149931
+ const moduleDir = path23.dirname(fileURLToPath5(moduleUrl));
149932
+ const distDir = path23.basename(moduleDir) === "cli" ? path23.dirname(moduleDir) : path23.basename(moduleDir) === "runtime" && path23.basename(path23.dirname(moduleDir)) === "src" ? path23.join(path23.dirname(path23.dirname(moduleDir)), "dist") : moduleDir;
149933
+ return path23.join(distDir, "vector-backfill-runner.js");
149032
149934
  }
149033
149935
  function parseVectorBackfillRequest(raw) {
149034
149936
  let value;
@@ -149037,7 +149939,7 @@ function parseVectorBackfillRequest(raw) {
149037
149939
  } catch {
149038
149940
  throw new Error("Vector backfill runner received invalid JSON input");
149039
149941
  }
149040
- if (!value || typeof value !== "object" || !isNonEmptyString(value.projectId) || !isNonEmptyString(value.projectRoot) || !isNonEmptyString(value.dataDir) || !path22.isAbsolute(value.projectRoot) || !path22.isAbsolute(value.dataDir)) {
149942
+ if (!value || typeof value !== "object" || !isNonEmptyString(value.projectId) || !isNonEmptyString(value.projectRoot) || !isNonEmptyString(value.dataDir) || !path23.isAbsolute(value.projectRoot) || !path23.isAbsolute(value.dataDir)) {
149041
149943
  throw new Error("Vector backfill runner received an invalid request");
149042
149944
  }
149043
149945
  return {
@@ -150119,8 +151021,16 @@ var init_observations = __esm({
150119
151021
  });
150120
151022
 
150121
151023
  // src/store/session-store.ts
150122
- import path23 from "path";
150123
- import fs15 from "fs";
151024
+ var session_store_exports = {};
151025
+ __export(session_store_exports, {
151026
+ SessionGracefulDegrade: () => SessionGracefulDegrade,
151027
+ SessionSqliteStore: () => SessionSqliteStore,
151028
+ getSessionStore: () => getSessionStore,
151029
+ initSessionStore: () => initSessionStore,
151030
+ resetSessionStore: () => resetSessionStore
151031
+ });
151032
+ import path24 from "path";
151033
+ import fs16 from "fs";
150124
151034
  function sessionToRow(session) {
150125
151035
  return {
150126
151036
  id: session.id,
@@ -150149,6 +151059,10 @@ function getSessionStore() {
150149
151059
  }
150150
151060
  return _store3;
150151
151061
  }
151062
+ function resetSessionStore() {
151063
+ _store3 = null;
151064
+ _storeDataDir3 = null;
151065
+ }
150152
151066
  async function initSessionStore(dataDir) {
150153
151067
  if (_store3 && _storeDataDir3 === dataDir) return _store3;
150154
151068
  _store3 = null;
@@ -150202,10 +151116,10 @@ var init_session_store = __esm({
150202
151116
  async migrateFromJsonIfNeeded() {
150203
151117
  const count2 = this.db.prepare(`SELECT COUNT(*) AS cnt FROM sessions`).get();
150204
151118
  if (count2.cnt > 0) return;
150205
- const jsonPath = path23.join(this.dataDir, "sessions.json");
150206
- if (!fs15.existsSync(jsonPath)) return;
151119
+ const jsonPath = path24.join(this.dataDir, "sessions.json");
151120
+ if (!fs16.existsSync(jsonPath)) return;
150207
151121
  try {
150208
- const raw = fs15.readFileSync(jsonPath, "utf-8");
151122
+ const raw = fs16.readFileSync(jsonPath, "utf-8");
150209
151123
  const sessions = JSON.parse(raw);
150210
151124
  if (!Array.isArray(sessions) || sessions.length === 0) return;
150211
151125
  console.error(`[memorix] Migrating ${sessions.length} sessions from JSON to SQLite...`);
@@ -152001,827 +152915,6 @@ var init_session = __esm({
152001
152915
  }
152002
152916
  });
152003
152917
 
152004
- // src/memory/owner.ts
152005
- var owner_exports = {};
152006
- __export(owner_exports, {
152007
- resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
152008
- });
152009
- import { randomUUID as randomUUID11 } from "crypto";
152010
- import { promises as fs17 } from "fs";
152011
- import path26 from "path";
152012
- function ownerPath(dataDir) {
152013
- const resolved = path26.resolve(dataDir);
152014
- const home = path26.basename(resolved).toLocaleLowerCase("en-US") === "data" ? path26.dirname(resolved) : resolved;
152015
- return path26.join(home, "memorix-user.json");
152016
- }
152017
- function normalizedOwnerId(value) {
152018
- const trimmed = value?.trim();
152019
- return trimmed && ID_PATTERN.test(trimmed) ? trimmed : void 0;
152020
- }
152021
- async function readOwnerFile(filePath) {
152022
- try {
152023
- const value = JSON.parse(await fs17.readFile(filePath, "utf8"));
152024
- const id = typeof value.id === "string" ? normalizedOwnerId(value.id) : void 0;
152025
- return id ? { id, source: "local-file" } : void 0;
152026
- } catch {
152027
- return void 0;
152028
- }
152029
- }
152030
- async function resolveLocalMemoryOwner(dataDir, options = {}) {
152031
- const configured = normalizedOwnerId(process.env.MEMORIX_USER_ID);
152032
- if (configured) return { id: configured, source: "environment" };
152033
- const filePath = ownerPath(dataDir);
152034
- const existing = await readOwnerFile(filePath);
152035
- if (existing || !options.create) return existing;
152036
- await fs17.mkdir(path26.dirname(filePath), { recursive: true });
152037
- const created = {
152038
- version: 1,
152039
- id: "local-" + randomUUID11(),
152040
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
152041
- };
152042
- try {
152043
- await fs17.writeFile(filePath, JSON.stringify(created, null, 2) + "\n", { encoding: "utf8", flag: "wx" });
152044
- return { id: created.id, source: "local-file" };
152045
- } catch (error) {
152046
- if (error?.code !== "EEXIST") throw error;
152047
- const concurrent = await readOwnerFile(filePath);
152048
- if (concurrent) return concurrent;
152049
- throw new Error("Memorix could not establish a valid local memory owner identity.");
152050
- }
152051
- }
152052
- var ID_PATTERN;
152053
- var init_owner = __esm({
152054
- "src/memory/owner.ts"() {
152055
- "use strict";
152056
- init_esm_shims();
152057
- ID_PATTERN = /^[A-Za-z0-9:_-]{3,160}$/;
152058
- }
152059
- });
152060
-
152061
- // src/memory/long-term-store.ts
152062
- import { randomUUID as randomUUID12 } from "crypto";
152063
- function optionalText6(value) {
152064
- return typeof value === "string" && value.trim() ? value : void 0;
152065
- }
152066
- function arrayValue2(value) {
152067
- if (typeof value !== "string" || !value) return [];
152068
- try {
152069
- const parsed = JSON.parse(value);
152070
- return Array.isArray(parsed) ? parsed.filter((item) => typeof item === "string") : [];
152071
- } catch {
152072
- return [];
152073
- }
152074
- }
152075
- function rowToMemory(row) {
152076
- return {
152077
- id: row.id,
152078
- originProjectId: row.originProjectId,
152079
- ownerId: row.ownerId,
152080
- scope: row.scope,
152081
- kind: row.kind,
152082
- state: row.state,
152083
- portability: row.portability,
152084
- title: row.title,
152085
- content: row.content,
152086
- facts: arrayValue2(row.factsJson),
152087
- tags: arrayValue2(row.tagsJson),
152088
- ...optionalText6(row.applicability) ? { applicability: row.applicability } : {},
152089
- origin: row.origin,
152090
- createdAt: row.createdAt,
152091
- updatedAt: row.updatedAt,
152092
- ...optionalText6(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
152093
- ...optionalText6(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
152094
- ...optionalText6(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
152095
- ...optionalText6(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
152096
- ...optionalText6(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
152097
- accessCount: Number(row.accessCount ?? 0),
152098
- ...optionalText6(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
152099
- };
152100
- }
152101
- function rowToEvidence2(row) {
152102
- return {
152103
- id: row.id,
152104
- memoryId: row.memoryId,
152105
- kind: row.kind,
152106
- referenceId: row.referenceId,
152107
- relation: row.relation,
152108
- ...optionalText6(row.locator) ? { locator: row.locator } : {},
152109
- ...optionalText6(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
152110
- createdAt: row.createdAt
152111
- };
152112
- }
152113
- function rowToEvent2(row) {
152114
- return {
152115
- id: row.id,
152116
- memoryId: row.memoryId,
152117
- kind: row.kind,
152118
- ...optionalText6(row.fromState) ? { fromState: row.fromState } : {},
152119
- ...optionalText6(row.toState) ? { toState: row.toState } : {},
152120
- ...optionalText6(row.detail) ? { detail: row.detail } : {},
152121
- createdAt: row.createdAt
152122
- };
152123
- }
152124
- var LongTermMemoryStore;
152125
- var init_long_term_store = __esm({
152126
- "src/memory/long-term-store.ts"() {
152127
- "use strict";
152128
- init_esm_shims();
152129
- init_sqlite_db();
152130
- LongTermMemoryStore = class {
152131
- db = null;
152132
- async init(dataDir) {
152133
- this.db = getDatabase(dataDir);
152134
- }
152135
- transaction(fn) {
152136
- return this.db.transaction(fn)();
152137
- }
152138
- get(id) {
152139
- const row = this.db.prepare("SELECT * FROM long_term_memories WHERE id = ?").get(id);
152140
- return row ? rowToMemory(row) : void 0;
152141
- }
152142
- list(options = {}) {
152143
- const limit2 = Math.max(1, Math.min(1e3, Math.floor(options.limit ?? 500)));
152144
- const clauses = [];
152145
- const params = [];
152146
- if (options.ownerId) {
152147
- clauses.push("ownerId = ?");
152148
- params.push(options.ownerId);
152149
- }
152150
- if (options.originProjectId) {
152151
- clauses.push("originProjectId = ?");
152152
- params.push(options.originProjectId);
152153
- }
152154
- const where = clauses.length ? " WHERE " + clauses.join(" AND ") : "";
152155
- const rows = this.db.prepare(
152156
- "SELECT * FROM long_term_memories" + where + " ORDER BY updatedAt DESC, id LIMIT ?"
152157
- ).all(...params, limit2);
152158
- return rows.map(rowToMemory);
152159
- }
152160
- insert(memory) {
152161
- this.db.prepare(`
152162
- INSERT INTO long_term_memories (
152163
- id, originProjectId, ownerId, scope, kind, state, portability,
152164
- title, content, factsJson, tagsJson, applicability, origin,
152165
- createdAt, updatedAt, qualifiedAt, approvedAt, archivedAt,
152166
- supersededBy, lastValidatedAt, accessCount, lastAccessedAt
152167
- ) VALUES (
152168
- @id, @originProjectId, @ownerId, @scope, @kind, @state, @portability,
152169
- @title, @content, @factsJson, @tagsJson, @applicability, @origin,
152170
- @createdAt, @updatedAt, @qualifiedAt, @approvedAt, @archivedAt,
152171
- @supersededBy, @lastValidatedAt, @accessCount, @lastAccessedAt
152172
- )
152173
- `).run({
152174
- ...memory,
152175
- factsJson: JSON.stringify(memory.facts),
152176
- tagsJson: JSON.stringify(memory.tags),
152177
- applicability: memory.applicability ?? null,
152178
- qualifiedAt: memory.qualifiedAt ?? null,
152179
- approvedAt: memory.approvedAt ?? null,
152180
- archivedAt: memory.archivedAt ?? null,
152181
- supersededBy: memory.supersededBy ?? null,
152182
- lastValidatedAt: memory.lastValidatedAt ?? null,
152183
- lastAccessedAt: memory.lastAccessedAt ?? null
152184
- });
152185
- }
152186
- update(memory) {
152187
- this.db.prepare(`
152188
- UPDATE long_term_memories SET
152189
- scope = @scope,
152190
- kind = @kind,
152191
- state = @state,
152192
- portability = @portability,
152193
- title = @title,
152194
- content = @content,
152195
- factsJson = @factsJson,
152196
- tagsJson = @tagsJson,
152197
- applicability = @applicability,
152198
- updatedAt = @updatedAt,
152199
- qualifiedAt = @qualifiedAt,
152200
- approvedAt = @approvedAt,
152201
- archivedAt = @archivedAt,
152202
- supersededBy = @supersededBy,
152203
- lastValidatedAt = @lastValidatedAt,
152204
- accessCount = @accessCount,
152205
- lastAccessedAt = @lastAccessedAt
152206
- WHERE id = @id
152207
- `).run({
152208
- ...memory,
152209
- factsJson: JSON.stringify(memory.facts),
152210
- tagsJson: JSON.stringify(memory.tags),
152211
- applicability: memory.applicability ?? null,
152212
- qualifiedAt: memory.qualifiedAt ?? null,
152213
- approvedAt: memory.approvedAt ?? null,
152214
- archivedAt: memory.archivedAt ?? null,
152215
- supersededBy: memory.supersededBy ?? null,
152216
- lastValidatedAt: memory.lastValidatedAt ?? null,
152217
- lastAccessedAt: memory.lastAccessedAt ?? null
152218
- });
152219
- }
152220
- insertEvidence(input) {
152221
- const evidence = {
152222
- id: randomUUID12(),
152223
- ...input,
152224
- createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
152225
- };
152226
- this.db.prepare(`
152227
- INSERT INTO long_term_memory_evidence (
152228
- id, memoryId, kind, referenceId, relation, locator, capturedHash, createdAt
152229
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
152230
- `).run(
152231
- evidence.id,
152232
- evidence.memoryId,
152233
- evidence.kind,
152234
- evidence.referenceId,
152235
- evidence.relation,
152236
- evidence.locator ?? null,
152237
- evidence.capturedHash ?? null,
152238
- evidence.createdAt
152239
- );
152240
- return evidence;
152241
- }
152242
- listEvidence(memoryId) {
152243
- return this.db.prepare(`
152244
- SELECT * FROM long_term_memory_evidence WHERE memoryId = ? ORDER BY createdAt ASC, id
152245
- `).all(memoryId).map(rowToEvidence2);
152246
- }
152247
- recordEvent(input) {
152248
- const event = {
152249
- id: randomUUID12(),
152250
- ...input,
152251
- createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
152252
- };
152253
- this.db.prepare(`
152254
- INSERT INTO long_term_memory_events (id, memoryId, kind, fromState, toState, detail, createdAt)
152255
- VALUES (?, ?, ?, ?, ?, ?, ?)
152256
- `).run(
152257
- event.id,
152258
- event.memoryId,
152259
- event.kind,
152260
- event.fromState ?? null,
152261
- event.toState ?? null,
152262
- event.detail ?? null,
152263
- event.createdAt
152264
- );
152265
- return event;
152266
- }
152267
- listEvents(memoryId) {
152268
- return this.db.prepare(`
152269
- SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
152270
- `).all(memoryId).map(rowToEvent2);
152271
- }
152272
- markAccess(ids, at = (/* @__PURE__ */ new Date()).toISOString()) {
152273
- const unique2 = [...new Set(ids.filter(Boolean))];
152274
- if (unique2.length === 0) return;
152275
- const statement = this.db.prepare(`
152276
- UPDATE long_term_memories
152277
- SET accessCount = accessCount + 1, lastAccessedAt = ?
152278
- WHERE id = ?
152279
- `);
152280
- this.db.transaction(() => {
152281
- for (const id of unique2) statement.run(at, id);
152282
- })();
152283
- }
152284
- };
152285
- }
152286
- });
152287
-
152288
- // src/memory/long-term-types.ts
152289
- var LONG_TERM_MEMORY_KINDS, LONG_TERM_MEMORY_SCOPES, LONG_TERM_MEMORY_PORTABILITIES, LONG_TERM_MEMORY_EVIDENCE_KINDS, LONG_TERM_MEMORY_EVIDENCE_RELATIONS;
152290
- var init_long_term_types = __esm({
152291
- "src/memory/long-term-types.ts"() {
152292
- "use strict";
152293
- init_esm_shims();
152294
- LONG_TERM_MEMORY_KINDS = ["episodic", "semantic", "procedural"];
152295
- LONG_TERM_MEMORY_SCOPES = ["project", "user", "team"];
152296
- LONG_TERM_MEMORY_PORTABILITIES = ["project-bound", "portable"];
152297
- LONG_TERM_MEMORY_EVIDENCE_KINDS = [
152298
- "observation",
152299
- "claim",
152300
- "workflow",
152301
- "session",
152302
- "checkpoint",
152303
- "git",
152304
- "code",
152305
- "test",
152306
- "run",
152307
- "document",
152308
- "manual",
152309
- "user"
152310
- ];
152311
- LONG_TERM_MEMORY_EVIDENCE_RELATIONS = [
152312
- "supports",
152313
- "verifies",
152314
- "derives",
152315
- "user-confirmed"
152316
- ];
152317
- }
152318
- });
152319
-
152320
- // src/memory/long-term.ts
152321
- var long_term_exports = {};
152322
- __export(long_term_exports, {
152323
- approveLongTermMemory: () => approveLongTermMemory,
152324
- archiveLongTermMemory: () => archiveLongTermMemory,
152325
- canReadLongTermMemory: () => canReadLongTermMemory,
152326
- createLongTermMemoryCandidate: () => createLongTermMemoryCandidate,
152327
- createManualLongTermMemory: () => createManualLongTermMemory,
152328
- getLongTermMemoryDetail: () => getLongTermMemoryDetail,
152329
- isEligibleLongTermMemory: () => isEligibleLongTermMemory,
152330
- listLongTermMemories: () => listLongTermMemories,
152331
- promoteObservationToLongTermMemory: () => promoteObservationToLongTermMemory,
152332
- qualifyLongTermMemory: () => qualifyLongTermMemory,
152333
- renderLongTermMemorySummary: () => renderLongTermMemorySummary,
152334
- selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
152335
- supersedeLongTermMemory: () => supersedeLongTermMemory
152336
- });
152337
- import { randomUUID as randomUUID13 } from "crypto";
152338
- function isOneOf(value, values) {
152339
- return typeof value === "string" && values.includes(value);
152340
- }
152341
- function compactText2(value, field, max = MAX_TEXT_LENGTH) {
152342
- if (typeof value !== "string") throw new Error("Long-term memory " + field + " must be text.");
152343
- const safe = sanitizeCredentials(value).replace(/\s+/g, " ").trim();
152344
- if (!safe) throw new Error("Long-term memory " + field + " is required.");
152345
- if (safe.length > max) throw new Error("Long-term memory " + field + " is too long.");
152346
- return safe;
152347
- }
152348
- function compactList(values, field) {
152349
- if (!values) return [];
152350
- if (!Array.isArray(values)) throw new Error("Long-term memory " + field + " must be an array.");
152351
- return [...new Set(values.filter((value) => typeof value === "string").map((value) => compactText2(value, field, 500)))].slice(0, MAX_LIST_ITEMS);
152352
- }
152353
- function normalizeEvidence(input) {
152354
- if (!Array.isArray(input) || input.length === 0) {
152355
- throw new Error("A long-term memory requires at least one source evidence reference.");
152356
- }
152357
- return input.map((evidence) => {
152358
- if (!evidence || !isOneOf(evidence.kind, LONG_TERM_MEMORY_EVIDENCE_KINDS)) {
152359
- throw new Error("Long-term memory evidence kind is invalid.");
152360
- }
152361
- if (!isOneOf(evidence.relation, LONG_TERM_MEMORY_EVIDENCE_RELATIONS)) {
152362
- throw new Error("Long-term memory evidence relation is invalid.");
152363
- }
152364
- return {
152365
- kind: evidence.kind,
152366
- referenceId: compactText2(evidence.referenceId, "evidence reference", 1e3),
152367
- relation: evidence.relation,
152368
- ...evidence.locator ? { locator: compactText2(evidence.locator, "evidence locator", 1e3) } : {},
152369
- ...evidence.capturedHash ? { capturedHash: compactText2(evidence.capturedHash, "evidence hash", 1e3) } : {}
152370
- };
152371
- });
152372
- }
152373
- function assertScope(scope) {
152374
- if (!isOneOf(scope, LONG_TERM_MEMORY_SCOPES)) throw new Error("Long-term memory scope is invalid.");
152375
- }
152376
- function assertKind(kind) {
152377
- if (!isOneOf(kind, LONG_TERM_MEMORY_KINDS)) throw new Error("Long-term memory kind is invalid.");
152378
- }
152379
- function assertPortability(value) {
152380
- if (!isOneOf(value, LONG_TERM_MEMORY_PORTABILITIES)) {
152381
- throw new Error("Long-term memory portability is invalid.");
152382
- }
152383
- }
152384
- function assertPortableEvidence(scope, portability, evidence) {
152385
- if (portability !== "portable") return;
152386
- if (scope !== "user") {
152387
- throw new Error("Only user-scoped long-term memories may be portable across projects.");
152388
- }
152389
- if (evidence.some((item) => !PORTABLE_EVIDENCE_KINDS.has(item.kind))) {
152390
- 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.");
152391
- }
152392
- }
152393
- function requireTeamReader(scope, reader) {
152394
- if (scope === "team" && reader?.isTeamMember !== true) {
152395
- throw new Error("Team long-term memory requires an explicit active team identity for this project.");
152396
- }
152397
- }
152398
- function matchesScope(memory, reader) {
152399
- if (memory.scope === "project") return memory.originProjectId === reader.projectId;
152400
- if (memory.scope === "team") {
152401
- return memory.originProjectId === reader.projectId && reader.isTeamMember === true;
152402
- }
152403
- if (!reader.ownerId || memory.ownerId !== reader.ownerId) return false;
152404
- return memory.portability === "portable" || memory.originProjectId === reader.projectId;
152405
- }
152406
- function canReadLongTermMemory(memory, reader) {
152407
- return matchesScope(memory, reader);
152408
- }
152409
- function isEligibleLongTermMemory(memory) {
152410
- return memory.state === "qualified" || memory.state === "approved";
152411
- }
152412
- function taskTerms(task) {
152413
- const matches = task.toLocaleLowerCase("en-US").match(/[\p{L}\p{N}_./:-]+/gu) ?? [];
152414
- return [...new Set(matches.filter((term) => term.length > 1 && !STOP_TERMS.has(term)))].slice(0, 16);
152415
- }
152416
- function kindFitScore(kind, task) {
152417
- const normalized = task.toLocaleLowerCase("en-US");
152418
- const hints = {
152419
- episodic: ["resume", "continue", "handoff", "previous", "session", "\u63A5\u624B", "\u7EE7\u7EED", "\u4EA4\u63A5", "\u4E0A\u6B21", "\u4F1A\u8BDD"],
152420
- semantic: ["why", "what", "architecture", "design", "decision", "reason", "\u4E3A\u4EC0\u4E48", "\u662F\u4EC0\u4E48", "\u67B6\u6784", "\u8BBE\u8BA1", "\u51B3\u7B56", "\u539F\u56E0"],
152421
- procedural: ["how", "steps", "procedure", "run", "release", "publish", "verify", "implement", "\u6D41\u7A0B", "\u6B65\u9AA4", "\u53D1\u5E03", "\u9A8C\u8BC1", "\u4FEE\u590D", "\u5B9E\u73B0"]
152422
- };
152423
- return hints[kind].some((hint) => normalized.includes(hint)) ? 1 : 0;
152424
- }
152425
- function validationFreshnessScore(memory) {
152426
- const validatedAt = memory.lastValidatedAt ?? memory.approvedAt ?? memory.qualifiedAt;
152427
- if (!validatedAt) return 0;
152428
- const time = Date.parse(validatedAt);
152429
- if (!Number.isFinite(time)) return 0;
152430
- const ageDays = Math.max(0, Date.now() - time) / (24 * 60 * 60 * 1e3);
152431
- if (ageDays <= 30) return 0.35;
152432
- if (ageDays <= 90) return 0.15;
152433
- return 0;
152434
- }
152435
- function scoreForTask(memory, task) {
152436
- const terms = taskTerms(task);
152437
- if (terms.length === 0) return void 0;
152438
- const title = memory.title.toLocaleLowerCase("en-US");
152439
- const content = memory.content.toLocaleLowerCase("en-US");
152440
- const facts = memory.facts.join(" ").toLocaleLowerCase("en-US");
152441
- const tags = memory.tags.join(" ").toLocaleLowerCase("en-US");
152442
- const applicability = (memory.applicability ?? "").toLocaleLowerCase("en-US");
152443
- let score = memory.state === "approved" ? 0.5 : 0;
152444
- const matched = [];
152445
- for (const term of terms) {
152446
- let termScore = 0;
152447
- if (title.includes(term)) termScore += 5;
152448
- if (tags.includes(term)) termScore += 4;
152449
- if (applicability.includes(term)) termScore += 3;
152450
- if (facts.includes(term)) termScore += 2;
152451
- if (content.includes(term)) termScore += 1;
152452
- if (termScore > 0) {
152453
- score += termScore;
152454
- matched.push(term);
152455
- }
152456
- }
152457
- if (matched.length === 0) return void 0;
152458
- score += kindFitScore(memory.kind, task);
152459
- score += validationFreshnessScore(memory);
152460
- const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
152461
- const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
152462
- return { score, reason: kindLabel + " matches " + matched.slice(0, 3).join(", ") + freshness };
152463
- }
152464
- function semanticText(memory) {
152465
- return sanitizeCredentials([
152466
- memory.title,
152467
- memory.applicability,
152468
- memory.tags.join(" "),
152469
- memory.facts.join(" "),
152470
- memory.content
152471
- ].filter((value) => Boolean(value)).join("\n")).replace(/\s+/g, " ").trim().slice(0, MAX_TEXT_LENGTH);
152472
- }
152473
- function cosineSimilarity(left, right) {
152474
- if (left.length === 0 || left.length !== right.length) return 0;
152475
- let dot = 0;
152476
- let leftMagnitude = 0;
152477
- let rightMagnitude = 0;
152478
- for (let index = 0; index < left.length; index += 1) {
152479
- const a = left[index];
152480
- const b = right[index];
152481
- if (!Number.isFinite(a) || !Number.isFinite(b)) return 0;
152482
- dot += a * b;
152483
- leftMagnitude += a * a;
152484
- rightMagnitude += b * b;
152485
- }
152486
- if (leftMagnitude === 0 || rightMagnitude === 0) return 0;
152487
- return dot / Math.sqrt(leftMagnitude * rightMagnitude);
152488
- }
152489
- function semanticSelection(memory, similarity, task) {
152490
- if (similarity < MIN_SEMANTIC_SIMILARITY) return void 0;
152491
- const kindLabel = memory.kind === "procedural" ? "procedure" : memory.kind === "semantic" ? "fact" : "episode";
152492
- const freshness = validationFreshnessScore(memory) > 0 ? "; recently validated" : "";
152493
- return {
152494
- score: similarity * 10 + (memory.state === "approved" ? 0.5 : 0) + kindFitScore(memory.kind, task) + validationFreshnessScore(memory),
152495
- reason: kindLabel + " semantic match " + similarity.toFixed(2) + freshness
152496
- };
152497
- }
152498
- async function resolveSemanticProvider(explicit) {
152499
- if (explicit !== void 0) return explicit;
152500
- try {
152501
- const { getEmbeddingProvider: getEmbeddingProvider2 } = await Promise.resolve().then(() => (init_provider(), provider_exports));
152502
- return await withTimeout(
152503
- getEmbeddingProvider2({ requestTimeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS, retry: false }),
152504
- SEMANTIC_RETRIEVAL_TIMEOUT_MS,
152505
- "Long-term semantic provider initialization"
152506
- );
152507
- } catch {
152508
- return null;
152509
- }
152510
- }
152511
- function createStore(dataDir) {
152512
- const store = new LongTermMemoryStore();
152513
- return store.init(dataDir).then(() => store);
152514
- }
152515
- async function createManualLongTermMemory(input) {
152516
- const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
152517
- if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
152518
- assertScope(input.scope);
152519
- const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID13(), relation: "supports" }];
152520
- return createLongTermMemoryWithDataDir({
152521
- dataDir: input.dataDir,
152522
- originProjectId: input.projectId,
152523
- ownerId: owner.id,
152524
- scope: input.scope,
152525
- kind: input.kind,
152526
- portability: input.portability,
152527
- title: input.title,
152528
- content: input.content,
152529
- facts: input.facts,
152530
- tags: input.tags,
152531
- applicability: input.applicability,
152532
- origin: "manual",
152533
- evidence,
152534
- reader: input.reader
152535
- });
152536
- }
152537
- async function promoteObservationToLongTermMemory(input) {
152538
- const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
152539
- if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
152540
- return createLongTermMemoryWithDataDir({
152541
- dataDir: input.dataDir,
152542
- originProjectId: input.observation.projectId,
152543
- ownerId: owner.id,
152544
- scope: input.scope,
152545
- kind: input.kind,
152546
- portability: "project-bound",
152547
- title: input.observation.title,
152548
- content: input.observation.narrative,
152549
- facts: input.observation.facts,
152550
- tags: input.tags ?? input.observation.concepts,
152551
- applicability: input.applicability,
152552
- origin: input.observation.source === "git" ? "git" : "agent",
152553
- evidence: [{
152554
- kind: "observation",
152555
- referenceId: "obs:" + input.observation.projectId + ":" + input.observation.id,
152556
- relation: "derives"
152557
- }],
152558
- reader: input.reader
152559
- });
152560
- }
152561
- async function createLongTermMemoryCandidate(input) {
152562
- return createLongTermMemoryWithDataDir(input);
152563
- }
152564
- async function createLongTermMemoryWithDataDir(input) {
152565
- assertScope(input.scope);
152566
- assertKind(input.kind);
152567
- const portability = input.portability ?? "project-bound";
152568
- assertPortability(portability);
152569
- requireTeamReader(input.scope, input.reader);
152570
- const evidenceInputs = normalizeEvidence(input.evidence);
152571
- assertPortableEvidence(input.scope, portability, evidenceInputs);
152572
- const now3 = (/* @__PURE__ */ new Date()).toISOString();
152573
- const memory = {
152574
- id: randomUUID13(),
152575
- originProjectId: compactText2(input.originProjectId, "origin project id", 1e3),
152576
- ownerId: compactText2(input.ownerId, "owner id", 160),
152577
- scope: input.scope,
152578
- kind: input.kind,
152579
- state: "candidate",
152580
- portability,
152581
- title: compactText2(input.title, "title", 500),
152582
- content: compactText2(input.content, "content"),
152583
- facts: compactList(input.facts, "facts"),
152584
- tags: compactList(input.tags, "tags"),
152585
- ...input.applicability ? { applicability: compactText2(input.applicability, "applicability", 1e3) } : {},
152586
- origin: input.origin ?? "manual",
152587
- createdAt: now3,
152588
- updatedAt: now3,
152589
- accessCount: 0
152590
- };
152591
- const store = await createStore(input.dataDir);
152592
- const evidence = store.transaction(() => {
152593
- store.insert(memory);
152594
- const written = evidenceInputs.map((item) => store.insertEvidence({ memoryId: memory.id, ...item, createdAt: now3 }));
152595
- store.recordEvent({
152596
- memoryId: memory.id,
152597
- kind: "created",
152598
- toState: "candidate",
152599
- detail: "Created as a source-backed long-term memory candidate.",
152600
- createdAt: now3
152601
- });
152602
- return written;
152603
- });
152604
- return { memory, evidence };
152605
- }
152606
- function transitionDetail(value) {
152607
- return compactText2(value, "transition reason", 1e3);
152608
- }
152609
- async function transitionMemory(input) {
152610
- const store = await createStore(input.dataDir);
152611
- return store.transaction(() => {
152612
- const current = store.get(input.id);
152613
- if (!current) throw new Error("Long-term memory was not found.");
152614
- if (current.state !== input.expected) {
152615
- throw new Error("Long-term memory must be " + input.expected + " before it can be " + input.next + ".");
152616
- }
152617
- const evidence = store.listEvidence(current.id);
152618
- if (evidence.length === 0) throw new Error("Long-term memory cannot advance without source evidence.");
152619
- const now3 = (/* @__PURE__ */ new Date()).toISOString();
152620
- const next = {
152621
- ...current,
152622
- state: input.next,
152623
- updatedAt: now3,
152624
- lastValidatedAt: now3,
152625
- ...input.next === "qualified" ? { qualifiedAt: now3 } : { approvedAt: now3 }
152626
- };
152627
- store.update(next);
152628
- store.recordEvent({
152629
- memoryId: next.id,
152630
- kind: input.event,
152631
- fromState: current.state,
152632
- toState: next.state,
152633
- detail: transitionDetail(input.reason),
152634
- createdAt: now3
152635
- });
152636
- return next;
152637
- });
152638
- }
152639
- async function qualifyLongTermMemory(input) {
152640
- return transitionMemory({ ...input, expected: "candidate", next: "qualified", event: "qualified" });
152641
- }
152642
- async function approveLongTermMemory(input) {
152643
- return transitionMemory({ ...input, expected: "qualified", next: "approved", event: "approved" });
152644
- }
152645
- async function archiveLongTermMemory(input) {
152646
- const store = await createStore(input.dataDir);
152647
- return store.transaction(() => {
152648
- const current = store.get(input.id);
152649
- if (!current) throw new Error("Long-term memory was not found.");
152650
- if (current.state === "archived" || current.state === "superseded") {
152651
- throw new Error("Long-term memory is already inactive.");
152652
- }
152653
- const now3 = (/* @__PURE__ */ new Date()).toISOString();
152654
- const next = { ...current, state: "archived", archivedAt: now3, updatedAt: now3 };
152655
- store.update(next);
152656
- store.recordEvent({
152657
- memoryId: next.id,
152658
- kind: "archived",
152659
- fromState: current.state,
152660
- toState: "archived",
152661
- detail: transitionDetail(input.reason),
152662
- createdAt: now3
152663
- });
152664
- return next;
152665
- });
152666
- }
152667
- async function supersedeLongTermMemory(input) {
152668
- const store = await createStore(input.dataDir);
152669
- return store.transaction(() => {
152670
- const current = store.get(input.id);
152671
- if (!current) throw new Error("Long-term memory was not found.");
152672
- if (current.state === "archived" || current.state === "superseded") {
152673
- throw new Error("Long-term memory is already inactive.");
152674
- }
152675
- if (current.id === input.supersededBy) {
152676
- throw new Error("Long-term memory cannot supersede itself.");
152677
- }
152678
- const replacement = store.get(input.supersededBy);
152679
- if (!replacement || !isEligibleLongTermMemory(replacement)) {
152680
- throw new Error("Replacement long-term memory must be qualified or approved.");
152681
- }
152682
- if (replacement.scope !== current.scope) {
152683
- throw new Error("Replacement long-term memory must use the same scope.");
152684
- }
152685
- if (current.scope === "user" && replacement.ownerId !== current.ownerId) {
152686
- throw new Error("User long-term memory may only be superseded by the same local owner.");
152687
- }
152688
- if (current.scope !== "user" && replacement.originProjectId !== current.originProjectId) {
152689
- throw new Error("Project and team long-term memory may only be superseded within the same project.");
152690
- }
152691
- const now3 = (/* @__PURE__ */ new Date()).toISOString();
152692
- const next = {
152693
- ...current,
152694
- state: "superseded",
152695
- supersededBy: replacement.id,
152696
- updatedAt: now3
152697
- };
152698
- store.update(next);
152699
- store.recordEvent({
152700
- memoryId: next.id,
152701
- kind: "superseded",
152702
- fromState: current.state,
152703
- toState: "superseded",
152704
- detail: transitionDetail(input.reason),
152705
- createdAt: now3
152706
- });
152707
- return next;
152708
- });
152709
- }
152710
- async function listLongTermMemories(input) {
152711
- const store = await createStore(input.dataDir);
152712
- return store.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: store.listEvidence(memory.id) }));
152713
- }
152714
- async function getLongTermMemoryDetail(input) {
152715
- const store = await createStore(input.dataDir);
152716
- const memory = store.get(input.id);
152717
- if (!memory || !canReadLongTermMemory(memory, input.reader)) {
152718
- throw new Error("Long-term memory was not found in the active scope.");
152719
- }
152720
- store.markAccess([memory.id]);
152721
- return { memory, evidence: store.listEvidence(memory.id), events: store.listEvents(memory.id) };
152722
- }
152723
- async function selectLongTermMemoriesForTask(input) {
152724
- const task = input.task?.trim();
152725
- if (!task) return [];
152726
- const owner = await resolveLocalMemoryOwner(input.dataDir, { create: false });
152727
- const reader = {
152728
- projectId: input.projectId,
152729
- ...owner ? { ownerId: owner.id } : {},
152730
- ...input.agentId ? { agentId: input.agentId } : {},
152731
- ...input.isTeamMember ? { isTeamMember: true } : {}
152732
- };
152733
- const store = await createStore(input.dataDir);
152734
- const eligible = store.list({ limit: 1e3 }).filter((memory) => isEligibleLongTermMemory(memory) && canReadLongTermMemory(memory, reader));
152735
- let selected = eligible.map((memory) => {
152736
- const ranked = scoreForTask(memory, task);
152737
- return ranked ? {
152738
- memory,
152739
- evidence: store.listEvidence(memory.id),
152740
- score: ranked.score,
152741
- reason: ranked.reason
152742
- } : void 0;
152743
- }).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));
152744
- if (selected.length === 0 && eligible.length > 0) {
152745
- const provider2 = await resolveSemanticProvider(input.embeddingProvider);
152746
- const candidates = eligible.slice(0, MAX_SEMANTIC_CANDIDATES);
152747
- if (provider2 && candidates.length > 0) {
152748
- try {
152749
- const vectors = await withTimeout(
152750
- provider2.embedBatch([task, ...candidates.map(semanticText)], {
152751
- timeoutMs: SEMANTIC_RETRIEVAL_TIMEOUT_MS,
152752
- retry: false
152753
- }),
152754
- SEMANTIC_RETRIEVAL_TIMEOUT_MS,
152755
- "Long-term semantic retrieval"
152756
- );
152757
- const query = vectors[0];
152758
- if (Array.isArray(query)) {
152759
- selected = candidates.map((memory, index) => {
152760
- const vector = vectors[index + 1];
152761
- const ranked = Array.isArray(vector) ? semanticSelection(memory, cosineSimilarity(query, vector), task) : void 0;
152762
- return ranked ? {
152763
- memory,
152764
- evidence: store.listEvidence(memory.id),
152765
- score: ranked.score,
152766
- reason: ranked.reason
152767
- } : void 0;
152768
- }).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));
152769
- }
152770
- } catch {
152771
- }
152772
- }
152773
- }
152774
- selected = selected.slice(0, Math.max(1, Math.min(input.limit ?? 3, 5)));
152775
- store.markAccess(selected.map((item) => item.memory.id));
152776
- return selected;
152777
- }
152778
- function renderLongTermMemorySummary(memory, maxTokens = 22) {
152779
- const source = [memory.title, memory.applicability, memory.content].filter(Boolean).join(": ");
152780
- const safe = sanitizeCredentials(source).replace(/\s+/g, " ").trim();
152781
- return countTextTokens(safe) <= maxTokens ? safe : truncateToTokenBudget(safe, maxTokens);
152782
- }
152783
- var MAX_TEXT_LENGTH, MAX_LIST_ITEMS, MAX_SEMANTIC_CANDIDATES, SEMANTIC_RETRIEVAL_TIMEOUT_MS, MIN_SEMANTIC_SIMILARITY, PORTABLE_EVIDENCE_KINDS, STOP_TERMS;
152784
- var init_long_term = __esm({
152785
- "src/memory/long-term.ts"() {
152786
- "use strict";
152787
- init_esm_shims();
152788
- init_token_budget();
152789
- init_timeout();
152790
- init_secret_filter();
152791
- init_owner();
152792
- init_long_term_store();
152793
- init_long_term_types();
152794
- MAX_TEXT_LENGTH = 12e3;
152795
- MAX_LIST_ITEMS = 40;
152796
- MAX_SEMANTIC_CANDIDATES = 48;
152797
- SEMANTIC_RETRIEVAL_TIMEOUT_MS = 1800;
152798
- MIN_SEMANTIC_SIMILARITY = 0.58;
152799
- PORTABLE_EVIDENCE_KINDS = /* @__PURE__ */ new Set(["manual", "user"]);
152800
- STOP_TERMS = /* @__PURE__ */ new Set([
152801
- "the",
152802
- "and",
152803
- "for",
152804
- "with",
152805
- "from",
152806
- "that",
152807
- "this",
152808
- "into",
152809
- "when",
152810
- "what",
152811
- "\u5982\u4F55",
152812
- "\u4EC0\u4E48",
152813
- "\u8FD9\u4E2A",
152814
- "\u90A3\u4E2A",
152815
- "\u6211\u4EEC",
152816
- "\u9879\u76EE",
152817
- "\u8FDB\u884C",
152818
- "\u9700\u8981",
152819
- "\u7EE7\u7EED",
152820
- "\u5904\u7406"
152821
- ]);
152822
- }
152823
- });
152824
-
152825
152918
  // src/knowledge/workset.ts
152826
152919
  function unique(values) {
152827
152920
  return [...new Set(values.filter(Boolean))];
@@ -153029,6 +153122,37 @@ function renderTaskWorksetPrompt(input) {
153029
153122
  trust: "source-backed"
153030
153123
  });
153031
153124
  appendLine(lines, "Task lens: " + input.lens, maxTokens, omitted, "lens");
153125
+ if (input.alwaysOn) {
153126
+ const hasAlwaysOn = input.alwaysOn.profile.length > 0 || Boolean(input.alwaysOn.state) || input.alwaysOn.durable.length > 0;
153127
+ if (hasAlwaysOn) {
153128
+ appendLine(lines, "", maxTokens, omitted, "always-on-heading");
153129
+ appendLine(lines, "You and this workspace", maxTokens, omitted, "always-on-heading");
153130
+ for (const profile of input.alwaysOn.profile.slice(0, 2)) {
153131
+ appendLine(lines, "- " + short(profile, 26), maxTokens, omitted, "always-on-profile", selected, {
153132
+ kind: "memory",
153133
+ id: "profile",
153134
+ reason: "user profile memory",
153135
+ trust: "source-backed"
153136
+ });
153137
+ }
153138
+ if (input.alwaysOn.state) {
153139
+ appendLine(lines, "- Recently: " + short(input.alwaysOn.state, 40), maxTokens, omitted, "always-on-state", selected, {
153140
+ kind: "continuation",
153141
+ id: "workspace-state",
153142
+ reason: "latest session summary for this workspace",
153143
+ trust: "historical"
153144
+ });
153145
+ }
153146
+ for (const durable of input.alwaysOn.durable.slice(0, 2)) {
153147
+ appendLine(lines, "- " + short(durable, 28), maxTokens, omitted, "always-on-durable", selected, {
153148
+ kind: "durable-memory",
153149
+ id: "durable-always",
153150
+ reason: "recent durable memory for this workspace",
153151
+ trust: "source-backed"
153152
+ });
153153
+ }
153154
+ }
153155
+ }
153032
153156
  const hasContinuation = Boolean(
153033
153157
  input.continuation?.previousSession || (input.continuation?.memories.length ?? 0) > 0 || input.continuation?.compactCheckpoint
153034
153158
  );
@@ -153499,6 +153623,7 @@ async function buildTaskWorkset(input) {
153499
153623
  version: "1.3",
153500
153624
  task,
153501
153625
  lens: input.lens,
153626
+ ...input.alwaysOn && (input.alwaysOn.profile.length > 0 || input.alwaysOn.state || input.alwaysOn.durable.length > 0) ? { alwaysOn: input.alwaysOn } : {},
153502
153627
  currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
153503
153628
  ...continuation ? { continuation } : {},
153504
153629
  ...input.codeState ? { codeState: short(input.codeState, 28) } : {},
@@ -154651,6 +154776,33 @@ function activeProjectObservations(observations2, projectId) {
154651
154776
  function deliveryEligibleProjectObservations(observations2, projectId) {
154652
154777
  return activeProjectObservations(observations2, projectId).filter((observation) => isEligibleForAutomaticDelivery(observation));
154653
154778
  }
154779
+ async function buildAlwaysOnBlock(input) {
154780
+ const profile = filterReadableObservations(input.eligible, input.reader).filter((observation) => observation.visibility === "personal" && observation.entityName === "user-profile").slice(0, 2).map((observation) => compactContinuationText(observation.title, 22));
154781
+ let state;
154782
+ try {
154783
+ await initSessionStore(input.dataDir);
154784
+ const { getSessionStore: getSessionStore2 } = await Promise.resolve().then(() => (init_session_store(), session_store_exports));
154785
+ const sessions = await getSessionStore2().loadByProject(input.projectId);
154786
+ const latest = sessions.filter((session) => session.endedAt && session.summary?.trim()).sort((a, b) => Date.parse(b.endedAt ?? "") - Date.parse(a.endedAt ?? ""))[0];
154787
+ if (latest?.summary) state = compactContinuationText(latest.summary, 40);
154788
+ } catch {
154789
+ }
154790
+ const durable = [];
154791
+ try {
154792
+ const items = await listLongTermMemories({
154793
+ dataDir: input.dataDir,
154794
+ reader: {
154795
+ projectId: input.projectId,
154796
+ ...input.reader.agentId ? { agentId: input.reader.agentId } : {},
154797
+ ...input.reader.isTeamMember ? { isTeamMember: true } : {}
154798
+ },
154799
+ limit: 10
154800
+ });
154801
+ durable.push(...items.filter((item) => item.memory.state === "approved").sort((a, b) => (b.memory.updatedAt ?? "").localeCompare(a.memory.updatedAt ?? "")).slice(0, 2).map((item) => item.memory.kind + ": " + compactContinuationText(item.memory.title, 22)));
154802
+ } catch {
154803
+ }
154804
+ return { profile, state, durable };
154805
+ }
154654
154806
  function decideRefresh(input) {
154655
154807
  if (input.mode === "never") {
154656
154808
  return { performed: false, reason: "disabled", message: "Automatic project scan disabled." };
@@ -154855,12 +155007,19 @@ async function buildAutoProjectContext(input) {
154855
155007
  };
154856
155008
  }
154857
155009
  }
155010
+ const alwaysOn = await buildAlwaysOnBlock({
155011
+ dataDir: input.dataDir,
155012
+ projectId: input.project.id,
155013
+ reader: input.reader ?? { projectId: input.project.id },
155014
+ eligible: deliveryEligibleProjectObservations(input.observations, input.project.id)
155015
+ });
154858
155016
  const workset = await buildTaskWorkset({
154859
155017
  projectId: input.project.id,
154860
155018
  dataDir: input.dataDir,
154861
155019
  ...task ? { task } : {},
154862
155020
  lens: lens.id,
154863
155021
  startHere,
155022
+ ...alwaysOn.profile.length > 0 || alwaysOn.state || alwaysOn.durable.length > 0 ? { alwaysOn } : {},
154864
155023
  ...externalOutline ? { semanticCode: externalOutline } : {},
154865
155024
  providerQuality: providerQuality2,
154866
155025
  currentFacts: worksetFactLines(currentFacts),
@@ -155043,7 +155202,16 @@ function formatAutoProjectContextSummary(context) {
155043
155202
  lensLine(context),
155044
155203
  "",
155045
155204
  ...formatCurrentFactsLines(context.currentFacts),
155046
- "",
155205
+ ""
155206
+ ].filter(Boolean);
155207
+ if (context.workset.alwaysOn && (context.workset.alwaysOn.profile.length > 0 || context.workset.alwaysOn.state || context.workset.alwaysOn.durable.length > 0)) {
155208
+ lines.push("You and this workspace");
155209
+ for (const profile of context.workset.alwaysOn.profile.slice(0, 2)) lines.push(`- ${profile}`);
155210
+ if (context.workset.alwaysOn.state) lines.push(`- Recently: ${context.workset.alwaysOn.state}`);
155211
+ for (const durable of context.workset.alwaysOn.durable.slice(0, 2)) lines.push(`- ${durable}`);
155212
+ lines.push("");
155213
+ }
155214
+ lines.push(...[
155047
155215
  `- Code memory: ${context.overview.code.files} files / ${context.overview.code.symbols} symbols / ${context.overview.code.refs} memory links`,
155048
155216
  `- Code provider: ${context.providerQuality.selected} (${context.providerQuality.selectedQuality})`,
155049
155217
  `- Languages: ${formatLanguages(context.overview)}`,
@@ -155052,7 +155220,7 @@ function formatAutoProjectContextSummary(context) {
155052
155220
  `- Refresh: ${context.refresh.message}`,
155053
155221
  "",
155054
155222
  "Start here"
155055
- ].filter(Boolean);
155223
+ ].filter(Boolean));
155056
155224
  if (startHere.length > 0) {
155057
155225
  startHere.forEach((path34, index) => lines.push(`${index + 1}. ${path34}`));
155058
155226
  } else {
@@ -155176,6 +155344,8 @@ var init_auto_context = __esm({
155176
155344
  init_store();
155177
155345
  init_admission();
155178
155346
  init_session();
155347
+ init_long_term();
155348
+ init_visibility();
155179
155349
  init_session_store();
155180
155350
  init_task_lens();
155181
155351
  DEFAULT_MAX_AGE_MS = 10 * 60 * 1e3;
@@ -158126,8 +158296,8 @@ async function handleApi(req, res, dataDir, projectId, projectName, baseDir, pro
158126
158296
  const { promises: fsP } = await import("fs");
158127
158297
  const registryPath = path30.join(baseDir, ".project-aliases.json");
158128
158298
  const raw = await fsP.readFile(registryPath, "utf-8");
158129
- const registry = JSON.parse(raw);
158130
- aliasGroups = registry.groups || [];
158299
+ const registry2 = JSON.parse(raw);
158300
+ aliasGroups = registry2.groups || [];
158131
158301
  } catch {
158132
158302
  }
158133
158303
  const currentGroup = aliasGroups.find((g) => g.aliases?.includes(effectiveProjectId) || g.canonical === effectiveProjectId);
@@ -160280,7 +160450,7 @@ async function installOfficialSkillsForAgent(agent, projectRoot, global2 = false
160280
160450
  const dirs = AGENT_SKILL_DIRS[agent];
160281
160451
  const relativeDir = global2 ? dirs?.global : dirs?.project;
160282
160452
  if (!relativeDir) return [];
160283
- const root = global2 ? os3.homedir() : projectRoot;
160453
+ const root = global2 ? agent === "dsh" ? process.env.DSH_HOME?.trim() || path32.join(os3.homedir(), ".dsh") : os3.homedir() : projectRoot;
160284
160454
  const skillPaths = [];
160285
160455
  for (const skillEntry of OFFICIAL_MEMORIX_SKILLS) {
160286
160456
  const skillPath = path32.join(root, relativeDir, skillEntry.name, "SKILL.md");
@@ -160512,6 +160682,8 @@ function getProjectConfigPath(agent, projectRoot) {
160512
160682
  return path32.join(projectRoot, "AGENTS.md");
160513
160683
  case "trae":
160514
160684
  return path32.join(projectRoot, ".trae", "rules", "project_rules.md");
160685
+ case "dsh":
160686
+ return path32.join(projectRoot, "AGENTS.md");
160515
160687
  case "opencode":
160516
160688
  return path32.join(projectRoot, ".opencode", "plugins", "memorix.js");
160517
160689
  case "pi":
@@ -160557,6 +160729,8 @@ function getGlobalConfigPath(agent) {
160557
160729
  return path32.join(home, ".omp", "agent", "packages", "memorix", "extensions", "memorix.js");
160558
160730
  case "trae":
160559
160731
  return path32.join(home, ".trae", "rules", "project_rules.md");
160732
+ case "dsh":
160733
+ return path32.join(process.env.DSH_HOME?.trim() || path32.join(home, ".dsh"), "AGENTS.md");
160560
160734
  default:
160561
160735
  return path32.join(home, ".memorix", "hooks.json");
160562
160736
  }
@@ -160581,6 +160755,8 @@ function getAgentRulesPath(agent, root, global2 = false) {
160581
160755
  return path32.join(root, ".gemini", "GEMINI.md");
160582
160756
  case "trae":
160583
160757
  return path32.join(root, ".trae", "rules", "project_rules.md");
160758
+ case "dsh":
160759
+ return path32.join(process.env.DSH_HOME?.trim() || path32.join(root, ".dsh"), "AGENTS.md");
160584
160760
  default:
160585
160761
  return path32.join(root, ".agent", "rules", "memorix.md");
160586
160762
  }
@@ -160605,6 +160781,8 @@ function getAgentRulesPath(agent, root, global2 = false) {
160605
160781
  return path32.join(root, "GEMINI.md");
160606
160782
  case "trae":
160607
160783
  return path32.join(root, ".trae", "rules", "project_rules.md");
160784
+ case "dsh":
160785
+ return path32.join(root, "AGENTS.md");
160608
160786
  default:
160609
160787
  return path32.join(root, ".agent", "rules", "memorix.md");
160610
160788
  }
@@ -160687,6 +160865,12 @@ async function detectInstalledAgents() {
160687
160865
  agents.push("trae");
160688
160866
  } catch {
160689
160867
  }
160868
+ const dshDir = process.env.DSH_HOME?.trim() || path32.join(home, ".dsh");
160869
+ try {
160870
+ await fs21.access(dshDir);
160871
+ agents.push("dsh");
160872
+ } catch {
160873
+ }
160690
160874
  return agents;
160691
160875
  }
160692
160876
  async function installHooks(agent, projectRoot, global2 = false) {
@@ -160769,6 +160953,19 @@ async function installHooks(agent, projectRoot, global2 = false) {
160769
160953
  generated: { note: "Trae has no hooks system, only rules (.trae/rules/project_rules.md) installed" }
160770
160954
  };
160771
160955
  }
160956
+ case "dsh": {
160957
+ const rulesPath = await installAgentRules(agent, projectRoot, global2);
160958
+ const skillPaths2 = await installOfficialSkillsForAgent(agent, projectRoot, global2);
160959
+ return {
160960
+ agent,
160961
+ configPath: rulesPath,
160962
+ events: [],
160963
+ generated: {
160964
+ note: "DeepSeek Harness has no hook system \u2014 installed AGENTS.md guidance and skills; the MCP row is installed by `memorix setup --agent dsh`.",
160965
+ ...skillPaths2.length > 0 ? { skillPaths: skillPaths2, skillPath: skillPaths2[0] } : {}
160966
+ }
160967
+ };
160968
+ }
160772
160969
  case "opencode": {
160773
160970
  const pluginContent = generateOpenCodePlugin();
160774
160971
  const pluginPath = global2 ? getGlobalConfigPath(agent) : getProjectConfigPath(agent, projectRoot);
@@ -160903,7 +161100,7 @@ async function installAgentRules(agent, projectRoot, global2 = false) {
160903
161100
  const rulesPath = getAgentRulesPath(agent, rulesRoot, global2);
160904
161101
  try {
160905
161102
  await fs21.mkdir(path32.dirname(rulesPath), { recursive: true });
160906
- if (agent === "claude" || agent === "codex" || agent === "opencode" || agent === "antigravity" || agent === "gemini-cli") {
161103
+ if (agent === "claude" || agent === "codex" || agent === "opencode" || agent === "antigravity" || agent === "gemini-cli" || agent === "dsh") {
160907
161104
  try {
160908
161105
  const existing = await fs21.readFile(rulesPath, "utf-8");
160909
161106
  await fs21.writeFile(rulesPath, mergeMemorixRulesContent(existing, rulesContent), "utf-8");
@@ -161016,13 +161213,28 @@ alwaysApply: true
161016
161213
  '- For "why" decisions, use `memorix_store_reasoning`',
161017
161214
  '- 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`.',
161018
161215
  "- 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.",
161216
+ '- Record the user profile: the user\u2019s role, expertise, preferences, and goals. Save these with `entityName: "user-profile"` and `visibility: "personal"` so they stay private and appear in every brief as the "who you are" context.',
161019
161217
  "",
161020
161218
  "**Don't store:** greetings, simple file reads, trivial commands (ls, pwd, git status).",
161021
161219
  "",
161220
+ "**Only store what a future session cannot re-derive.** Code structure, file contents, and Git history are live in the checkout \u2014 do not store facts already visible there. A memory earns its place by capturing the why, the context, or a conclusion the checkout alone cannot show.",
161221
+ "",
161222
+ `**Record what worked, not only what failed.** Store validated approaches and explicit user confirmations alongside corrections. Saving only failures drifts behavior away from what the user already accepted; a clear "yes, that's right" is feedback worth keeping too.`,
161223
+ "",
161224
+ "**Recalled memory is a claim about the past.** A memory naming a specific file, function, or flag describes the past at write time \u2014 check the file exists or grep the symbol before recommending it. If the user says to ignore or not use memory, proceed as if memory were empty: do not apply, cite, compare, or mention stored content.",
161225
+ "",
161022
161226
  "## When to resolve memory",
161023
161227
  "",
161024
161228
  "Use `memorix_resolve` when a task is done or a bug is fixed. This keeps future searches focused on active work instead of surfacing completed items.",
161025
161229
  "",
161230
+ "## End sessions with a summary",
161231
+ "",
161232
+ "When a session finishes, call `memorix_session_end` with a short structured summary so the next agent can resume. Recommended sections:",
161233
+ "- **Goal** \u2014 what this session was working on",
161234
+ "- **Discoveries** \u2014 findings, gotchas, learnings",
161235
+ "- **Accomplished** \u2014 completed items, plus PENDING items for the next session",
161236
+ "- **Relevant Files** \u2014 paths and what changed",
161237
+ "",
161026
161238
  "## Tools quick reference",
161027
161239
  "",
161028
161240
  "| Tool | Use when |",
@@ -161192,7 +161404,10 @@ var init_installers = __esm({
161192
161404
  windsurf: { project: path32.join(".windsurf", "skills"), global: path32.join(".windsurf", "skills") },
161193
161405
  kiro: { project: path32.join(".kiro", "skills"), global: path32.join(".kiro", "skills") },
161194
161406
  opencode: { project: path32.join(".opencode", "skills"), global: path32.join(".config", "opencode", "skills") },
161195
- trae: { project: path32.join(".trae", "skills"), global: path32.join(".trae", "skills") }
161407
+ trae: { project: path32.join(".trae", "skills"), global: path32.join(".trae", "skills") },
161408
+ // DSH's user skill root is <harness home>/skills; the global root below is
161409
+ // resolved to $DSH_HOME (or ~/.dsh) for dsh by installOfficialSkillsForAgent.
161410
+ dsh: { project: path32.join(".dsh", "skills"), global: "skills" }
161196
161411
  };
161197
161412
  PACKAGE_OWNED_HOOK_AGENTS = /* @__PURE__ */ new Set(["openclaw", "hermes", "omp"]);
161198
161413
  }
@@ -162614,8 +162829,8 @@ init_persistence();
162614
162829
 
162615
162830
  // src/rules/syncer.ts
162616
162831
  init_esm_shims();
162617
- import { promises as fs16 } from "fs";
162618
- import path24 from "path";
162832
+ import { promises as fs17 } from "fs";
162833
+ import path25 from "path";
162619
162834
 
162620
162835
  // src/rules/adapters/cursor.ts
162621
162836
  init_esm_shims();
@@ -163278,8 +163493,8 @@ var RulesSyncer = class {
163278
163493
  const found = await this.findFiles(scanPath);
163279
163494
  for (const filePath of found) {
163280
163495
  try {
163281
- const content = await fs16.readFile(filePath, "utf-8");
163282
- const relativePath = path24.relative(this.projectRoot, filePath).replace(/\\/g, "/");
163496
+ const content = await fs17.readFile(filePath, "utf-8");
163497
+ const relativePath = path25.relative(this.projectRoot, filePath).replace(/\\/g, "/");
163283
163498
  const parsed = entry.adapter.parse(relativePath, content);
163284
163499
  rules.push(...parsed);
163285
163500
  } catch {
@@ -163347,7 +163562,7 @@ var RulesSyncer = class {
163347
163562
  const entries = [];
163348
163563
  for (const adapter of this.adapters.values()) {
163349
163564
  const absolutePaths = adapter.filePatterns.map(
163350
- (p) => path24.join(this.projectRoot, p)
163565
+ (p) => path25.join(this.projectRoot, p)
163351
163566
  );
163352
163567
  entries.push({ adapter, paths: absolutePaths });
163353
163568
  }
@@ -163355,13 +163570,13 @@ var RulesSyncer = class {
163355
163570
  }
163356
163571
  /** Find files matching a glob-like path (simple implementation) */
163357
163572
  async findFiles(pattern) {
163358
- const dir = path24.dirname(pattern);
163359
- const fileGlob = path24.basename(pattern);
163573
+ const dir = path25.dirname(pattern);
163574
+ const fileGlob = path25.basename(pattern);
163360
163575
  try {
163361
- const stat4 = await fs16.stat(dir);
163576
+ const stat4 = await fs17.stat(dir);
163362
163577
  if (!stat4.isDirectory()) {
163363
163578
  try {
163364
- await fs16.access(pattern);
163579
+ await fs17.access(pattern);
163365
163580
  return [pattern];
163366
163581
  } catch {
163367
163582
  return [];
@@ -163369,7 +163584,7 @@ var RulesSyncer = class {
163369
163584
  }
163370
163585
  } catch {
163371
163586
  try {
163372
- await fs16.access(pattern);
163587
+ await fs17.access(pattern);
163373
163588
  return [pattern];
163374
163589
  } catch {
163375
163590
  return [];
@@ -163377,16 +163592,16 @@ var RulesSyncer = class {
163377
163592
  }
163378
163593
  if (fileGlob.includes("*")) {
163379
163594
  try {
163380
- const files = await fs16.readdir(dir);
163595
+ const files = await fs17.readdir(dir);
163381
163596
  const ext = fileGlob.replace("*", "");
163382
- return files.filter((f3) => ext ? f3.endsWith(ext) : true).map((f3) => path24.join(dir, f3));
163597
+ return files.filter((f3) => ext ? f3.endsWith(ext) : true).map((f3) => path25.join(dir, f3));
163383
163598
  } catch {
163384
163599
  return [];
163385
163600
  }
163386
163601
  }
163387
163602
  try {
163388
- await fs16.access(path24.join(dir, fileGlob));
163389
- return [path24.join(dir, fileGlob)];
163603
+ await fs17.access(path25.join(dir, fileGlob));
163604
+ return [path25.join(dir, fileGlob)];
163390
163605
  } catch {
163391
163606
  return [];
163392
163607
  }
@@ -164928,13 +165143,47 @@ function parseFormationTimeoutMs(raw) {
164928
165143
  init_timeout();
164929
165144
  init_secret_filter();
164930
165145
 
165146
+ // src/search/surfaced-registry.ts
165147
+ init_esm_shims();
165148
+ var MAX_KEYS = 64;
165149
+ var MAX_IDS = 200;
165150
+ var registry = /* @__PURE__ */ new Map();
165151
+ function touch(key) {
165152
+ const ids = registry.get(key);
165153
+ if (!ids) return [];
165154
+ registry.delete(key);
165155
+ registry.set(key, ids);
165156
+ return ids;
165157
+ }
165158
+ function getSurfacedIds(key) {
165159
+ return [...touch(key)];
165160
+ }
165161
+ function recordSurfacedIds(key, ids) {
165162
+ if (ids.length === 0) return;
165163
+ let list = registry.get(key) ?? [];
165164
+ const known = new Set(list);
165165
+ for (const id of ids) {
165166
+ if (known.has(id)) continue;
165167
+ known.add(id);
165168
+ list.push(id);
165169
+ }
165170
+ if (list.length > MAX_IDS) {
165171
+ list = list.slice(list.length - MAX_IDS);
165172
+ }
165173
+ registry.set(key, list);
165174
+ if (registry.size > MAX_KEYS) {
165175
+ const oldestKey = registry.keys().next().value;
165176
+ if (oldestKey !== void 0 && oldestKey !== key) registry.delete(oldestKey);
165177
+ }
165178
+ }
165179
+
164931
165180
  // src/server/request-context.ts
164932
165181
  init_esm_shims();
164933
- import path25 from "path";
165182
+ import path26 from "path";
164934
165183
  function resolveRoot(projectRoot) {
164935
165184
  const value = projectRoot.trim();
164936
165185
  if (!value) throw new Error("Project binding requires a non-empty project root");
164937
- return path25.resolve(value);
165186
+ return path26.resolve(value);
164938
165187
  }
164939
165188
  var ProjectBindingController = class {
164940
165189
  current;
@@ -165325,6 +165574,12 @@ async function createMemorixServer(cwd, existingServer, sharedTeam, options = {}
165325
165574
  kind: "consolidation",
165326
165575
  dedupeKey: "startup-consolidation"
165327
165576
  });
165577
+ lifecycle.enqueueLongTermMaintenance({
165578
+ dataDir: projectDir2,
165579
+ projectId: project.id,
165580
+ source: "startup",
165581
+ queue
165582
+ });
165328
165583
  }
165329
165584
  try {
165330
165585
  const { CodeGraphStore: CodeGraphStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
@@ -165374,7 +165629,7 @@ The path should point to a directory containing a .git folder.`
165374
165629
  };
165375
165630
  const server = existingServer ?? new McpServer({
165376
165631
  name: "memorix",
165377
- version: true ? "1.4.4" : "1.0.1"
165632
+ version: true ? "1.4.6" : "1.0.1"
165378
165633
  });
165379
165634
  const originalRegisterTool = server.registerTool.bind(server);
165380
165635
  server.registerTool = ((name, ...args) => {
@@ -165859,7 +166114,7 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
165859
166114
  let longTermNote = "";
165860
166115
  if (longTerm) {
165861
166116
  try {
165862
- const { promoteObservationToLongTermMemory: promoteObservationToLongTermMemory2 } = await Promise.resolve().then(() => (init_long_term(), long_term_exports));
166117
+ const { promoteObservationToLongTermMemory: promoteObservationToLongTermMemory2, maybeAutoQualifyLongTermMemory: maybeAutoQualifyLongTermMemory2 } = await Promise.resolve().then(() => (init_long_term(), long_term_exports));
165863
166118
  const promoted = await promoteObservationToLongTermMemory2({
165864
166119
  dataDir: projectDir2,
165865
166120
  observation: obs,
@@ -165873,7 +166128,24 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
165873
166128
  ...reader.isTeamMember ? { isTeamMember: true } : {}
165874
166129
  }
165875
166130
  });
165876
- longTermNote = `
166131
+ const autoQualified = await maybeAutoQualifyLongTermMemory2({
166132
+ dataDir: projectDir2,
166133
+ id: promoted.memory.id,
166134
+ sourceDetail: "explicit"
166135
+ });
166136
+ if (autoQualified) {
166137
+ try {
166138
+ const { enqueueLongTermMaintenance: enqueueLongTermMaintenance2 } = await Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports));
166139
+ enqueueLongTermMaintenance2({
166140
+ dataDir: projectDir2,
166141
+ projectId: project.id,
166142
+ source: "long-term:" + promoted.memory.id
166143
+ });
166144
+ } catch {
166145
+ }
166146
+ }
166147
+ longTermNote = autoQualified ? `
166148
+ Long-term memory: ${promoted.memory.id} (${promoted.memory.kind}/${promoted.memory.scope}, auto-qualified) and now enters briefs as durable context. Audit with \`memorix memory long-term list\`.` : `
165877
166149
  Long-term candidate: ${promoted.memory.id} (${promoted.memory.kind}/${promoted.memory.scope}). Review it with the CLI before it is delivered automatically.`;
165878
166150
  } catch (longTermError) {
165879
166151
  longTermNote = `
@@ -166069,6 +166341,13 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
166069
166341
  const boundary = requireExplicitAutopilotExpansion("memorix_search", purpose);
166070
166342
  if (boundary) return boundary;
166071
166343
  }
166344
+ let surfacedKey = `project:${project.id}`;
166345
+ try {
166346
+ const { getActiveSession: getActiveSession2 } = await Promise.resolve().then(() => (init_session(), session_exports));
166347
+ const active = await getActiveSession2(projectDir2, project.id);
166348
+ if (active) surfacedKey = `session:${active.id}`;
166349
+ } catch {
166350
+ }
166072
166351
  return withFreshIndex(async () => {
166073
166352
  const safeLimit2 = limit2 != null ? coerceNumber(limit2, 20) : void 0;
166074
166353
  const safeMaxTokens = maxTokens != null ? coerceNumber(maxTokens, 0) : void 0;
@@ -166086,7 +166365,8 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
166086
166365
  status: status ?? "active",
166087
166366
  source,
166088
166367
  quality,
166089
- reader: getObservationReader(scope === "global" ? "global" : "project")
166368
+ reader: getObservationReader(scope === "global" ? "global" : "project"),
166369
+ surfacedIds: getSurfacedIds(surfacedKey)
166090
166370
  });
166091
166371
  let result;
166092
166372
  try {
@@ -166105,6 +166385,7 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
166105
166385
  }
166106
166386
  throw error;
166107
166387
  }
166388
+ recordSurfacedIds(surfacedKey, result.entries.map((entry) => entry.id));
166108
166389
  const activeBoundary = getActiveAutopilotRetrievalBoundary();
166109
166390
  if (scope !== "global" && activeBoundary && !force && result.entries.length > 0 && result.entries.every((entry) => activeBoundary.coveredObservationIds.has(entry.id))) {
166110
166391
  const duplicate = blockCoveredAutopilotEvidence("memorix_search", result.entries.map((entry) => entry.id), force);
@@ -169067,13 +169348,26 @@ ${lines.join("\n")}` }] };
169067
169348
  if (bytes.length >= 12 && Buffer.from(bytes.subarray(0, 4)).toString("ascii") === "RIFF" && Buffer.from(bytes.subarray(8, 12)).toString("ascii") === "WEBP") return "image/webp";
169068
169349
  return void 0;
169069
169350
  }
169351
+ const mediaGenerationEnabled = process.env.MEMORIX_MCP_MEDIA_GENERATION === "1";
169352
+ const mediaTranscriptionEnabled = process.env.MEMORIX_MCP_MEDIA_TRANSCRIPTION === "1";
169353
+ const mediaGenerationOrTranscription = mediaGenerationEnabled || mediaTranscriptionEnabled;
169070
169354
  server.registerTool(
169071
169355
  "memorix_media",
169072
169356
  {
169073
169357
  title: "Manage Controlled Media",
169074
169358
  description: "Use the controlled local media library for an explicit import, attachment, inspection, or MiniMax generation request. Assets stay outside the Git worktree and enter normal memory only when attach is explicitly true. Use the CLI for destructive removal, quota cleanup, and direct generation. MCP generation is disabled by default and requires MEMORIX_MCP_MEDIA_GENERATION=1 after the operator reviews provider billing.",
169075
169359
  inputSchema: {
169076
- action: z626.enum(["import", "attach", "list", "show", "derive-pdf", "derive-audio", "generate-image", "generate-video", "status", "cancel"]),
169360
+ action: z626.enum([
169361
+ "import",
169362
+ "attach",
169363
+ "list",
169364
+ "show",
169365
+ "derive-pdf",
169366
+ "status",
169367
+ "cancel",
169368
+ ...mediaTranscriptionEnabled ? ["derive-audio"] : [],
169369
+ ...mediaGenerationEnabled ? ["generate-image", "generate-video"] : []
169370
+ ]),
169077
169371
  path: z626.string().optional().describe("Explicit local image/audio/video/PDF path for import."),
169078
169372
  assetId: z626.string().optional().describe("Controlled MediaAsset ID for attach/show."),
169079
169373
  jobId: z626.string().optional().describe("Durable media job ID for status."),
@@ -169081,20 +169375,26 @@ ${lines.join("\n")}` }] };
169081
169375
  limit: z626.number().int().min(1).max(100).optional().describe("Maximum assets to list."),
169082
169376
  title: z626.string().optional().describe("Observation title when attaching generated/imported output."),
169083
169377
  narrative: z626.string().optional().describe("Short retrieval text when attaching an asset."),
169084
- prompt: z626.string().optional().describe("Explicit MiniMax generation prompt."),
169085
- image: z626.string().optional().describe("Base64-encoded reference image for image-to-image generation."),
169086
- model: z626.string().max(160).optional().describe("Provider model for the selected media action."),
169087
- provider: z626.enum(["openai", "groq"]).optional().describe("Explicit audio transcription provider."),
169088
- language: z626.string().max(32).optional().describe("Optional ISO-639-1 hint for audio transcription."),
169089
- region: z626.enum(["global", "cn"]).optional().describe("MiniMax deployment region."),
169090
- n: z626.number().int().min(1).max(4).optional().describe("Image output count."),
169091
- ratio: z626.enum(["adaptive", "1:1", "16:9", "4:3", "3:2", "2:3", "3:4", "9:16", "21:9"]).optional().describe("Image or video aspect ratio."),
169092
- width: z626.number().int().min(1).max(8192).optional().describe("Requested image width."),
169093
- height: z626.number().int().min(1).max(8192).optional().describe("Requested image height."),
169094
- duration: z626.union([z626.literal(5), z626.literal(10)]).optional().describe("MiniMax video duration in seconds."),
169095
169378
  maxPages: z626.number().int().min(1).max(100).optional().describe("Bounded PDF extraction page limit."),
169096
169379
  maxChars: z626.number().int().min(1).max(6e4).optional().describe("Bounded PDF extraction character limit."),
169097
- attach: z626.boolean().optional().describe("Attach generated/imported output to normal project memory explicitly.")
169380
+ attach: z626.boolean().optional().describe("Attach generated/imported output to normal project memory explicitly."),
169381
+ ...mediaGenerationOrTranscription ? {
169382
+ model: z626.string().max(160).optional().describe("Provider model for the selected media action."),
169383
+ prompt: z626.string().optional().describe("Explicit prompt for generation or transcription.")
169384
+ } : {},
169385
+ ...mediaTranscriptionEnabled ? {
169386
+ provider: z626.enum(["openai", "groq"]).optional().describe("Explicit audio transcription provider."),
169387
+ language: z626.string().max(32).optional().describe("Optional ISO-639-1 hint for audio transcription.")
169388
+ } : {},
169389
+ ...mediaGenerationEnabled ? {
169390
+ image: z626.string().optional().describe("Base64-encoded reference image for image-to-image generation."),
169391
+ region: z626.enum(["global", "cn"]).optional().describe("MiniMax deployment region."),
169392
+ n: z626.number().int().min(1).max(4).optional().describe("Image output count."),
169393
+ ratio: z626.enum(["adaptive", "1:1", "16:9", "4:3", "3:2", "2:3", "3:4", "9:16", "21:9"]).optional().describe("Image or video aspect ratio."),
169394
+ width: z626.number().int().min(1).max(8192).optional().describe("Requested image width."),
169395
+ height: z626.number().int().min(1).max(8192).optional().describe("Requested image height."),
169396
+ duration: z626.union([z626.literal(5), z626.literal(10)]).optional().describe("MiniMax video duration in seconds.")
169397
+ } : {}
169098
169398
  }
169099
169399
  },
169100
169400
  async ({ action, path: assetPath, assetId, jobId, kind, limit: limit2, title, narrative, prompt, image, model, provider: provider2, language, region, n, ratio, width, height, duration, maxPages, maxChars, attach }) => {