memorix 1.7.3 → 1.8.1

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 (73) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +1 -1
  3. package/README.zh-CN.md +1 -1
  4. package/dist/cli/index.js +1488 -270
  5. package/dist/dashboard/static/app.js +125 -27
  6. package/dist/dashboard/static/index.html +11 -1
  7. package/dist/dashboard/static/style.css +86 -0
  8. package/dist/index.d.ts +2 -2
  9. package/dist/index.js +927 -240
  10. package/dist/maintenance-runner.js +607 -68
  11. package/dist/media-audio-runner.js +602 -63
  12. package/dist/media-video-runner.js +607 -68
  13. package/dist/memcode-runtime/CHANGELOG.md +41 -0
  14. package/dist/sdk.js +926 -239
  15. package/dist/types.d.ts +8 -0
  16. package/dist/vector-backfill-runner.js +607 -68
  17. package/docs/1.2.4-PERSISTENT-MEMORY-DELIVERY.md +1 -1
  18. package/docs/1.8.0-RELEASE-CANDIDATE-SPEC.md +75 -0
  19. package/docs/API_REFERENCE.md +39 -1
  20. package/docs/ARCHITECTURE.md +3 -1
  21. package/docs/DASHBOARD.md +16 -0
  22. package/docs/DEVELOPMENT.md +3 -2
  23. package/docs/INTEGRATIONS.md +1 -1
  24. package/docs/README.md +15 -2
  25. package/package.json +1 -1
  26. package/plugins/antigravity/memorix/rules/memorix.md +1 -1
  27. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  28. package/plugins/claude/memorix/SKILL.md +1 -1
  29. package/plugins/claude/memorix/skills/memorix-memory/SKILL.md +2 -2
  30. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  31. package/plugins/codebuddy/memorix/skills/memorix-memory/SKILL.md +2 -2
  32. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  33. package/plugins/codex/memorix/skills/memorix-memory/SKILL.md +2 -2
  34. package/plugins/copilot/memorix/plugin.json +1 -1
  35. package/plugins/copilot/memorix/skills/memorix-memory/SKILL.md +2 -2
  36. package/plugins/cursor/memorix/skills/memorix-memory/SKILL.md +2 -2
  37. package/plugins/gemini/memorix/GEMINI.md +1 -1
  38. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  39. package/plugins/omp/memorix/package.json +1 -1
  40. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  41. package/plugins/pi/memorix/package.json +1 -1
  42. package/plugins/pi/memorix/skills/memorix-memory/SKILL.md +2 -2
  43. package/server.json +2 -2
  44. package/src/cli/capability-map.ts +2 -0
  45. package/src/cli/commands/context.ts +11 -0
  46. package/src/cli/commands/dashboard.ts +1 -1
  47. package/src/cli/commands/evidence.ts +56 -0
  48. package/src/cli/commands/feedback.ts +58 -0
  49. package/src/cli/commands/resume.ts +2 -0
  50. package/src/cli/commands/serve-http.ts +229 -13
  51. package/src/cli/fallback-budget.ts +59 -0
  52. package/src/cli/index.ts +5 -1
  53. package/src/compact/engine.ts +26 -1
  54. package/src/config/dotenv-loader.ts +17 -0
  55. package/src/dashboard/config-provenance.ts +17 -0
  56. package/src/dashboard/evidence.ts +63 -0
  57. package/src/dashboard/server.ts +178 -154
  58. package/src/dashboard/static/index.html +11 -1
  59. package/src/dashboard/static/style.css +86 -0
  60. package/src/hooks/installers/index.ts +1 -1
  61. package/src/hooks/official-skills.ts +3 -3
  62. package/src/hooks/rules/memorix-agent-rules.md +1 -1
  63. package/src/memory/feedback-model.ts +4 -0
  64. package/src/memory/feedback.ts +220 -0
  65. package/src/memory/observations.ts +19 -0
  66. package/src/memory/retention.ts +38 -5
  67. package/src/server/mcp-binding-store.ts +79 -0
  68. package/src/server/mcp-diagnostics.ts +40 -0
  69. package/src/server/tool-profile.ts +4 -0
  70. package/src/server.ts +125 -5
  71. package/src/store/evidence-store.ts +261 -0
  72. package/src/store/sqlite-db.ts +104 -0
  73. package/src/types.ts +8 -0
@@ -95,6 +95,8 @@ function loadEnvFile(filePath) {
95
95
  const parsed = parse(readFileSync(filePath, "utf-8"));
96
96
  for (const [key, value] of Object.entries(parsed)) {
97
97
  if (!(key in process.env)) {
98
+ loadedEnvKeys.add(key);
99
+ loadedEnvValues.set(key, value);
98
100
  process.env[key] = value;
99
101
  injectedKeys.add(key);
100
102
  }
@@ -107,6 +109,8 @@ function loadDotenv(projectRoot, options = {}) {
107
109
  resetDotenv();
108
110
  }
109
111
  loadedEnvFiles.length = 0;
112
+ loadedEnvKeys.clear();
113
+ loadedEnvValues.clear();
110
114
  if (projectRoot) {
111
115
  loadEnvFile(getProjectDotenvPath(projectRoot));
112
116
  }
@@ -122,11 +126,12 @@ function resetDotenv() {
122
126
  dotenvLoaded = false;
123
127
  dotenvProjectRoot = null;
124
128
  loadedEnvFiles.length = 0;
129
+ loadedEnvKeys.clear();
125
130
  }
126
131
  function getLoadedEnvFiles() {
127
132
  return loadedEnvFiles;
128
133
  }
129
- var dotenvLoaded, dotenvProjectRoot, loadedEnvFiles, injectedKeys;
134
+ var dotenvLoaded, dotenvProjectRoot, loadedEnvFiles, loadedEnvKeys, loadedEnvValues, injectedKeys;
130
135
  var init_dotenv_loader = __esm({
131
136
  "src/config/dotenv-loader.ts"() {
132
137
  "use strict";
@@ -135,6 +140,8 @@ var init_dotenv_loader = __esm({
135
140
  dotenvLoaded = false;
136
141
  dotenvProjectRoot = null;
137
142
  loadedEnvFiles = [];
143
+ loadedEnvKeys = /* @__PURE__ */ new Set();
144
+ loadedEnvValues = /* @__PURE__ */ new Map();
138
145
  injectedKeys = /* @__PURE__ */ new Set();
139
146
  }
140
147
  });
@@ -518,7 +525,7 @@ function closeAllDatabases() {
518
525
  _dbCache.delete(key);
519
526
  }
520
527
  }
521
- var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
528
+ var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_EVIDENCE_CARDS_TABLE, CREATE_EVIDENCE_CARD_EVENTS_TABLE, CREATE_MEMORY_FEEDBACK_STATES_TABLE, CREATE_MEMORY_FEEDBACK_EVENTS_TABLE, CREATE_MCP_BINDINGS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
522
529
  var init_sqlite_db = __esm({
523
530
  "src/store/sqlite-db.ts"() {
524
531
  "use strict";
@@ -1164,6 +1171,79 @@ CREATE TABLE IF NOT EXISTS compaction_checkpoints (
1164
1171
  created_at TEXT NOT NULL,
1165
1172
  updated_at TEXT NOT NULL
1166
1173
  );
1174
+ `;
1175
+ CREATE_EVIDENCE_CARDS_TABLE = `
1176
+ CREATE TABLE IF NOT EXISTS evidence_cards (
1177
+ id TEXT PRIMARY KEY,
1178
+ project_id TEXT NOT NULL,
1179
+ candidate_kind TEXT NOT NULL,
1180
+ candidate_id TEXT NOT NULL,
1181
+ title TEXT NOT NULL,
1182
+ summary TEXT NOT NULL DEFAULT '',
1183
+ entity_name TEXT,
1184
+ source_kind TEXT NOT NULL,
1185
+ source_ref TEXT NOT NULL,
1186
+ locator TEXT,
1187
+ captured_hash TEXT,
1188
+ session_id TEXT,
1189
+ status TEXT NOT NULL DEFAULT 'active',
1190
+ verification TEXT NOT NULL DEFAULT 'unverified',
1191
+ freshness TEXT NOT NULL DEFAULT 'current',
1192
+ stale_reason TEXT,
1193
+ files_json TEXT NOT NULL DEFAULT '[]',
1194
+ related_entities_json TEXT NOT NULL DEFAULT '[]',
1195
+ created_at TEXT NOT NULL,
1196
+ updated_at TEXT NOT NULL,
1197
+ UNIQUE(project_id, candidate_kind, candidate_id)
1198
+ );
1199
+ `;
1200
+ CREATE_EVIDENCE_CARD_EVENTS_TABLE = `
1201
+ CREATE TABLE IF NOT EXISTS evidence_card_events (
1202
+ id TEXT PRIMARY KEY,
1203
+ project_id TEXT NOT NULL,
1204
+ card_id TEXT NOT NULL,
1205
+ kind TEXT NOT NULL,
1206
+ detail TEXT,
1207
+ created_at TEXT NOT NULL,
1208
+ FOREIGN KEY (card_id) REFERENCES evidence_cards(id) ON DELETE CASCADE
1209
+ );
1210
+ `;
1211
+ CREATE_MEMORY_FEEDBACK_STATES_TABLE = `
1212
+ CREATE TABLE IF NOT EXISTS memory_feedback_states (
1213
+ project_id TEXT NOT NULL,
1214
+ candidate_kind TEXT NOT NULL,
1215
+ candidate_id TEXT NOT NULL,
1216
+ weight REAL NOT NULL DEFAULT 1.0,
1217
+ lifecycle_status TEXT NOT NULL DEFAULT 'active',
1218
+ updated_at TEXT NOT NULL,
1219
+ PRIMARY KEY (project_id, candidate_kind, candidate_id)
1220
+ );
1221
+ `;
1222
+ CREATE_MEMORY_FEEDBACK_EVENTS_TABLE = `
1223
+ CREATE TABLE IF NOT EXISTS memory_feedback_events (
1224
+ id TEXT PRIMARY KEY,
1225
+ project_id TEXT NOT NULL,
1226
+ candidate_kind TEXT NOT NULL,
1227
+ candidate_id TEXT NOT NULL,
1228
+ signal TEXT NOT NULL,
1229
+ actor TEXT,
1230
+ note TEXT,
1231
+ source_ref TEXT NOT NULL,
1232
+ target_event_id TEXT,
1233
+ delta REAL NOT NULL DEFAULT 0,
1234
+ observed_at TEXT NOT NULL
1235
+ );
1236
+ `;
1237
+ CREATE_MCP_BINDINGS_TABLE = `
1238
+ CREATE TABLE IF NOT EXISTS mcp_bindings (
1239
+ handle_id TEXT PRIMARY KEY,
1240
+ project_id TEXT NOT NULL,
1241
+ project_root TEXT NOT NULL,
1242
+ data_dir TEXT NOT NULL,
1243
+ created_at TEXT NOT NULL,
1244
+ last_used_at TEXT NOT NULL,
1245
+ expires_at TEXT
1246
+ );
1167
1247
  `;
1168
1248
  CREATE_INDEXES = `
1169
1249
  CREATE INDEX IF NOT EXISTS idx_observations_projectId ON observations(projectId);
@@ -1226,6 +1306,12 @@ CREATE INDEX IF NOT EXISTS idx_maintenance_targets_updated ON maintenance_target
1226
1306
  CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_project_recent ON compaction_checkpoints(project_id, status, completed_at DESC, pre_captured_at DESC);
1227
1307
  CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_session_pending ON compaction_checkpoints(project_id, session_id, agent, phase, status, pre_captured_at DESC);
1228
1308
  CREATE INDEX IF NOT EXISTS idx_compaction_checkpoints_source ON compaction_checkpoints(project_id, source_key);
1309
+ CREATE INDEX IF NOT EXISTS idx_evidence_cards_project ON evidence_cards(project_id, status, updated_at DESC);
1310
+ CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(project_id, candidate_kind, candidate_id);
1311
+ CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at);
1312
+ CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC);
1313
+ CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC);
1314
+ CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC);
1229
1315
  CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1230
1316
  ON maintenance_jobs(project_id, kind, dedupe_key)
1231
1317
  WHERE status IN ('pending', 'running', 'retry');
@@ -1381,6 +1467,22 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1381
1467
  }
1382
1468
  db2.exec("CREATE INDEX IF NOT EXISTS idx_media_jobs_source_asset ON media_jobs(project_id, source_asset_id, status)");
1383
1469
  }
1470
+ },
1471
+ {
1472
+ id: "1.8-context-control-plane",
1473
+ apply: (db2) => {
1474
+ db2.exec(CREATE_EVIDENCE_CARDS_TABLE);
1475
+ db2.exec(CREATE_EVIDENCE_CARD_EVENTS_TABLE);
1476
+ db2.exec(CREATE_MEMORY_FEEDBACK_STATES_TABLE);
1477
+ db2.exec(CREATE_MEMORY_FEEDBACK_EVENTS_TABLE);
1478
+ db2.exec(CREATE_MCP_BINDINGS_TABLE);
1479
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_cards_project ON evidence_cards(project_id, status, updated_at DESC)");
1480
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_cards_candidate ON evidence_cards(project_id, candidate_kind, candidate_id)");
1481
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_evidence_card_events_card ON evidence_card_events(card_id, created_at)");
1482
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_states_project ON memory_feedback_states(project_id, candidate_kind, updated_at DESC)");
1483
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_feedback_events_candidate ON memory_feedback_events(project_id, candidate_kind, candidate_id, observed_at DESC)");
1484
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_mcp_bindings_project ON mcp_bindings(project_id, last_used_at DESC)");
1485
+ }
1384
1486
  }
1385
1487
  ];
1386
1488
  _dbCache = /* @__PURE__ */ new Map();
@@ -7981,10 +8083,230 @@ var init_lifecycle = __esm({
7981
8083
  }
7982
8084
  });
7983
8085
 
8086
+ // src/store/evidence-store.ts
8087
+ import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
8088
+ function safeJson(value, fallback) {
8089
+ if (typeof value !== "string" || value.length === 0) return fallback;
8090
+ try {
8091
+ return JSON.parse(value);
8092
+ } catch {
8093
+ return fallback;
8094
+ }
8095
+ }
8096
+ function rowToCard(row) {
8097
+ return {
8098
+ id: String(row.id),
8099
+ projectId: String(row.project_id),
8100
+ candidateKind: row.candidate_kind,
8101
+ candidateId: String(row.candidate_id),
8102
+ title: String(row.title),
8103
+ summary: String(row.summary ?? ""),
8104
+ ...row.entity_name ? { entityName: String(row.entity_name) } : {},
8105
+ sourceKind: String(row.source_kind),
8106
+ sourceRef: String(row.source_ref),
8107
+ ...row.locator ? { locator: String(row.locator) } : {},
8108
+ ...row.captured_hash ? { capturedHash: String(row.captured_hash) } : {},
8109
+ ...row.session_id ? { sessionId: String(row.session_id) } : {},
8110
+ status: String(row.status ?? "active"),
8111
+ verification: row.verification,
8112
+ freshness: row.freshness,
8113
+ ...row.stale_reason ? { staleReason: String(row.stale_reason) } : {},
8114
+ files: safeJson(row.files_json, []),
8115
+ relatedEntities: safeJson(row.related_entities_json, []),
8116
+ createdAt: String(row.created_at),
8117
+ updatedAt: String(row.updated_at)
8118
+ };
8119
+ }
8120
+ function observationHash(observation) {
8121
+ return createHash3("sha256").update(JSON.stringify({
8122
+ projectId: observation.projectId,
8123
+ id: observation.id,
8124
+ title: observation.title,
8125
+ narrative: observation.narrative,
8126
+ facts: observation.facts,
8127
+ files: observation.filesModified,
8128
+ relatedEntities: observation.relatedEntities
8129
+ })).digest("hex");
8130
+ }
8131
+ function sourceKind(observation) {
8132
+ if (observation.source === "git" || observation.sourceDetail === "git-ingest") return "git";
8133
+ if (observation.sourceDetail === "hook") return "hook";
8134
+ return observation.source ?? "agent";
8135
+ }
8136
+ var EvidenceCardStore;
8137
+ var init_evidence_store = __esm({
8138
+ "src/store/evidence-store.ts"() {
8139
+ "use strict";
8140
+ init_esm_shims();
8141
+ init_sqlite_db();
8142
+ EvidenceCardStore = class {
8143
+ db = null;
8144
+ async init(dataDir) {
8145
+ this.db = getDatabase(dataDir);
8146
+ }
8147
+ requireDb() {
8148
+ if (!this.db) throw new Error("EvidenceCardStore is not initialized.");
8149
+ return this.db;
8150
+ }
8151
+ upsertObservation(observation) {
8152
+ const db2 = this.requireDb();
8153
+ const now3 = (/* @__PURE__ */ new Date()).toISOString();
8154
+ const card = {
8155
+ id: `evidence:observation:${observation.projectId}:${observation.id}`,
8156
+ projectId: observation.projectId,
8157
+ candidateKind: "observation",
8158
+ candidateId: String(observation.id),
8159
+ title: observation.title,
8160
+ summary: observation.narrative.slice(0, 500),
8161
+ entityName: observation.entityName,
8162
+ sourceKind: sourceKind(observation),
8163
+ sourceRef: `observation:${observation.id}`,
8164
+ locator: observation.filesModified?.join(", ") || `observation:${observation.id}`,
8165
+ capturedHash: observationHash(observation),
8166
+ ...observation.sessionId ? { sessionId: observation.sessionId } : {},
8167
+ status: observation.status ?? "active",
8168
+ verification: observation.status === "resolved" ? "verified" : "unverified",
8169
+ freshness: "current",
8170
+ files: observation.filesModified ?? [],
8171
+ relatedEntities: observation.relatedEntities ?? [],
8172
+ createdAt: observation.createdAt,
8173
+ updatedAt: now3
8174
+ };
8175
+ db2.prepare(`
8176
+ INSERT INTO evidence_cards (
8177
+ id, project_id, candidate_kind, candidate_id, title, summary, entity_name,
8178
+ source_kind, source_ref, locator, captured_hash, session_id, status,
8179
+ verification, freshness, stale_reason, files_json, related_entities_json,
8180
+ created_at, updated_at
8181
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?)
8182
+ ON CONFLICT(project_id, candidate_kind, candidate_id) DO UPDATE SET
8183
+ title = excluded.title,
8184
+ summary = excluded.summary,
8185
+ entity_name = excluded.entity_name,
8186
+ source_kind = excluded.source_kind,
8187
+ source_ref = excluded.source_ref,
8188
+ locator = excluded.locator,
8189
+ captured_hash = excluded.captured_hash,
8190
+ session_id = excluded.session_id,
8191
+ status = excluded.status,
8192
+ freshness = 'current',
8193
+ stale_reason = NULL,
8194
+ files_json = excluded.files_json,
8195
+ related_entities_json = excluded.related_entities_json,
8196
+ updated_at = excluded.updated_at
8197
+ `).run(
8198
+ card.id,
8199
+ card.projectId,
8200
+ card.candidateKind,
8201
+ card.candidateId,
8202
+ card.title,
8203
+ card.summary,
8204
+ card.entityName ?? null,
8205
+ card.sourceKind,
8206
+ card.sourceRef,
8207
+ card.locator ?? null,
8208
+ card.capturedHash ?? null,
8209
+ card.sessionId ?? null,
8210
+ card.status,
8211
+ card.verification,
8212
+ card.freshness,
8213
+ JSON.stringify(card.files),
8214
+ JSON.stringify(card.relatedEntities),
8215
+ card.createdAt,
8216
+ card.updatedAt
8217
+ );
8218
+ return this.get(card.projectId, card.candidateKind, card.candidateId) ?? card;
8219
+ }
8220
+ get(projectId, candidateKind, candidateId) {
8221
+ const row = this.requireDb().prepare(`
8222
+ SELECT * FROM evidence_cards WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
8223
+ `).get(projectId, candidateKind, candidateId);
8224
+ return row ? rowToCard(row) : void 0;
8225
+ }
8226
+ list(projectId, options = {}) {
8227
+ const limit2 = Math.min(100, Math.max(1, Math.floor(options.limit ?? 20)));
8228
+ const clauses = ["project_id = ?"];
8229
+ const args = [projectId];
8230
+ if (options.freshness) {
8231
+ clauses.push("freshness = ?");
8232
+ args.push(options.freshness);
8233
+ }
8234
+ if (options.status) {
8235
+ clauses.push("status = ?");
8236
+ args.push(options.status);
8237
+ }
8238
+ args.push(limit2);
8239
+ const rows = this.requireDb().prepare(`
8240
+ SELECT * FROM evidence_cards WHERE ${clauses.join(" AND ")} ORDER BY updated_at DESC, id DESC LIMIT ?
8241
+ `).all(...args);
8242
+ return rows.map(rowToCard);
8243
+ }
8244
+ syncObservations(observations2) {
8245
+ return observations2.map((observation) => this.upsertObservation(observation));
8246
+ }
8247
+ markStaleForPaths(projectId, paths, reason = "source file changed") {
8248
+ const normalized = new Set(paths.map((value) => value.replace(/\\/g, "/").toLowerCase()));
8249
+ if (normalized.size === 0) return 0;
8250
+ const db2 = this.requireDb();
8251
+ const rows = db2.prepare(`SELECT * FROM evidence_cards WHERE project_id = ? AND freshness != 'stale'`).all(projectId);
8252
+ const update2 = db2.prepare(`
8253
+ UPDATE evidence_cards SET freshness = 'stale', stale_reason = ?, updated_at = ?
8254
+ WHERE id = ?
8255
+ `);
8256
+ let changed = 0;
8257
+ const now3 = (/* @__PURE__ */ new Date()).toISOString();
8258
+ const run = db2.transaction(() => {
8259
+ for (const row of rows) {
8260
+ const files = safeJson(row.files_json, []);
8261
+ if (!files.some((file) => normalized.has(file.replace(/\\/g, "/").toLowerCase()))) continue;
8262
+ update2.run(reason, now3, row.id);
8263
+ changed++;
8264
+ }
8265
+ });
8266
+ run();
8267
+ return changed;
8268
+ }
8269
+ setVerification(projectId, cardId, verification) {
8270
+ this.requireDb().prepare(`
8271
+ UPDATE evidence_cards SET verification = ?, updated_at = ? WHERE project_id = ? AND id = ?
8272
+ `).run(verification, (/* @__PURE__ */ new Date()).toISOString(), projectId, cardId);
8273
+ }
8274
+ recordEvent(projectId, cardId, kind, detail) {
8275
+ const event = {
8276
+ id: randomUUID3(),
8277
+ projectId,
8278
+ cardId,
8279
+ kind,
8280
+ ...detail ? { detail: detail.slice(0, 2e3) } : {},
8281
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
8282
+ };
8283
+ this.requireDb().prepare(`
8284
+ INSERT INTO evidence_card_events (id, project_id, card_id, kind, detail, created_at)
8285
+ VALUES (?, ?, ?, ?, ?, ?)
8286
+ `).run(event.id, event.projectId, event.cardId, event.kind, event.detail ?? null, event.createdAt);
8287
+ return event;
8288
+ }
8289
+ listEvents(cardId, limit2 = 50) {
8290
+ const rows = this.requireDb().prepare(`
8291
+ SELECT * FROM evidence_card_events WHERE card_id = ? ORDER BY created_at DESC LIMIT ?
8292
+ `).all(cardId, Math.min(200, Math.max(1, Math.floor(limit2))));
8293
+ return rows.map((row) => ({
8294
+ id: String(row.id),
8295
+ projectId: String(row.project_id),
8296
+ cardId: String(row.card_id),
8297
+ kind: String(row.kind),
8298
+ ...row.detail ? { detail: String(row.detail) } : {},
8299
+ createdAt: String(row.created_at)
8300
+ }));
8301
+ }
8302
+ };
8303
+ }
8304
+ });
8305
+
7984
8306
  // src/codegraph/ids.ts
7985
- import { createHash as createHash3 } from "crypto";
8307
+ import { createHash as createHash4 } from "crypto";
7986
8308
  function digest(input) {
7987
- return createHash3("sha256").update(input).digest("hex").slice(0, 16);
8309
+ return createHash4("sha256").update(input).digest("hex").slice(0, 16);
7988
8310
  }
7989
8311
  function normalizeCodePath(path21) {
7990
8312
  return path21.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/");
@@ -8019,7 +8341,7 @@ var store_exports = {};
8019
8341
  __export(store_exports, {
8020
8342
  CodeGraphStore: () => CodeGraphStore
8021
8343
  });
8022
- import { randomUUID as randomUUID3 } from "crypto";
8344
+ import { randomUUID as randomUUID4 } from "crypto";
8023
8345
  import { posix as pathPosix } from "path";
8024
8346
  function rowToFile(row) {
8025
8347
  return {
@@ -8736,7 +9058,7 @@ var init_store = __esm({
8736
9058
  * so an interrupted scan cannot be advertised as complete.
8737
9059
  */
8738
9060
  recordCodeStateSnapshot(input) {
8739
- const id = randomUUID3();
9061
+ const id = randomUUID4();
8740
9062
  let snapshot;
8741
9063
  const tx = this.db.transaction(() => {
8742
9064
  const previous = this.db.prepare(
@@ -9068,6 +9390,16 @@ async function bindObservationCodeRefsBestEffort(observation) {
9068
9390
  } catch {
9069
9391
  }
9070
9392
  }
9393
+ async function persistEvidenceCard(observation) {
9394
+ if (!projectDir) return;
9395
+ try {
9396
+ const evidence = new EvidenceCardStore();
9397
+ await evidence.init(projectDir);
9398
+ evidence.upsertObservation(observation);
9399
+ } catch (error) {
9400
+ console.error(`[memorix] Evidence card projection failed for obs-${observation.id}: ${error instanceof Error ? error.message : String(error)}`);
9401
+ }
9402
+ }
9071
9403
  function queueClaimDerivation(observation) {
9072
9404
  const dataDir = projectDir;
9073
9405
  const isExplicit = observation.sourceDetail === "explicit";
@@ -9414,6 +9746,7 @@ async function storeObservation(input) {
9414
9746
  }
9415
9747
  if (!persistedCallbackInvoked) await input.onPersisted?.(observation);
9416
9748
  await bindObservationCodeRefsBestEffort(observation);
9749
+ await persistEvidenceCard(observation);
9417
9750
  queueObservationQualification(observation);
9418
9751
  if (resolveObservationVisibility(observation) === "project") {
9419
9752
  queueClaimDerivation(observation);
@@ -9506,6 +9839,7 @@ async function upsertObservation(existing, input, now3) {
9506
9839
  await store.update(existing);
9507
9840
  }
9508
9841
  await bindObservationCodeRefsBestEffort(existing);
9842
+ await persistEvidenceCard(existing);
9509
9843
  queueObservationQualification(existing);
9510
9844
  if (resolveObservationVisibility(existing) === "project") {
9511
9845
  queueClaimDerivation(existing);
@@ -9639,6 +9973,7 @@ async function resolveObservations(ids, status = "resolved") {
9639
9973
  await Promise.all(changed.map((observation) => tx.update(observation)));
9640
9974
  });
9641
9975
  }
9976
+ for (const observation of changed) await persistEvidenceCard(observation);
9642
9977
  return { resolved, notFound };
9643
9978
  }
9644
9979
  function getProjectObservations(projectId) {
@@ -9976,6 +10311,7 @@ var init_observations = __esm({
9976
10311
  init_secret_filter();
9977
10312
  init_lifecycle();
9978
10313
  init_visibility();
10314
+ init_evidence_store();
9979
10315
  observations = [];
9980
10316
  nextId = 1;
9981
10317
  projectDir = null;
@@ -9993,7 +10329,7 @@ var init_observations = __esm({
9993
10329
  });
9994
10330
 
9995
10331
  // src/knowledge/workspace-store.ts
9996
- import { randomUUID as randomUUID4 } from "crypto";
10332
+ import { randomUUID as randomUUID5 } from "crypto";
9997
10333
  function arrayValue(raw) {
9998
10334
  if (typeof raw !== "string" || !raw) return [];
9999
10335
  try {
@@ -10134,7 +10470,7 @@ var init_workspace_store = __esm({
10134
10470
  }
10135
10471
  createProposal(input) {
10136
10472
  const proposal = {
10137
- id: input.id ?? randomUUID4(),
10473
+ id: input.id ?? randomUUID5(),
10138
10474
  ...input,
10139
10475
  status: input.status ?? "pending",
10140
10476
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
@@ -10187,13 +10523,13 @@ __export(workspace_exports, {
10187
10523
  loadKnowledgeWorkspace: () => loadKnowledgeWorkspace,
10188
10524
  resolveKnowledgeWorkspaceFile: () => resolveKnowledgeWorkspaceFile
10189
10525
  });
10190
- import { createHash as createHash4 } from "crypto";
10526
+ import { createHash as createHash5 } from "crypto";
10191
10527
  import { execFile } from "child_process";
10192
10528
  import { promises as fs6 } from "fs";
10193
10529
  import path9 from "path";
10194
10530
  import { promisify } from "util";
10195
10531
  function hash(value) {
10196
- return createHash4("sha256").update(value).digest("hex");
10532
+ return createHash5("sha256").update(value).digest("hex");
10197
10533
  }
10198
10534
  function workspaceId(projectId, mode) {
10199
10535
  return "workspace:" + hash(projectId + ":" + mode).slice(0, 24);
@@ -10789,7 +11125,7 @@ Respond in JSON only:
10789
11125
  });
10790
11126
 
10791
11127
  // src/media/media-store.ts
10792
- import { randomUUID as randomUUID5 } from "crypto";
11128
+ import { randomUUID as randomUUID6 } from "crypto";
10793
11129
  function asOptionalText(value) {
10794
11130
  return typeof value === "string" && value.length > 0 ? value : void 0;
10795
11131
  }
@@ -10959,7 +11295,7 @@ var init_media_store = __esm({
10959
11295
  return { asset: this.getAsset(input.projectId, existing.id), deduplicated: true };
10960
11296
  }
10961
11297
  const asset = {
10962
- id: randomUUID5(),
11298
+ id: randomUUID6(),
10963
11299
  ...input,
10964
11300
  createdAt: now3,
10965
11301
  updatedAt: now3
@@ -11039,7 +11375,7 @@ var init_media_store = __esm({
11039
11375
  `).get(input.assetId, input.observationId ?? null, input.role);
11040
11376
  if (existing) return rowToLink(existing);
11041
11377
  const link = {
11042
- id: randomUUID5(),
11378
+ id: randomUUID6(),
11043
11379
  assetId: input.assetId,
11044
11380
  projectId: input.projectId,
11045
11381
  ...input.observationId !== void 0 ? { observationId: input.observationId } : {},
@@ -11078,7 +11414,7 @@ var init_media_store = __esm({
11078
11414
  return rowToDerivation(this.db.prepare("SELECT * FROM media_derivations WHERE id = ?").get(existing.id));
11079
11415
  }
11080
11416
  const derivation = {
11081
- id: randomUUID5(),
11417
+ id: randomUUID6(),
11082
11418
  ...input,
11083
11419
  content,
11084
11420
  ...error ? { error } : {},
@@ -11165,7 +11501,7 @@ var init_media_store = __esm({
11165
11501
  createJob(input) {
11166
11502
  const now3 = Date.now();
11167
11503
  const job = {
11168
- id: randomUUID5(),
11504
+ id: randomUUID6(),
11169
11505
  projectId: input.projectId,
11170
11506
  kind: input.kind,
11171
11507
  status: "queued",
@@ -11327,14 +11663,14 @@ var init_types2 = __esm({
11327
11663
  });
11328
11664
 
11329
11665
  // src/media/asset-store.ts
11330
- import { createHash as createHash5, randomUUID as randomUUID6 } from "crypto";
11666
+ import { createHash as createHash6, randomUUID as randomUUID7 } from "crypto";
11331
11667
  import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
11332
11668
  import path10 from "path";
11333
11669
  function mediaRoot(dataDir) {
11334
11670
  return path10.resolve(dataDir, "media");
11335
11671
  }
11336
11672
  function projectStorageKey(projectId) {
11337
- return createHash5("sha256").update(projectId).digest("hex").slice(0, 16);
11673
+ return createHash6("sha256").update(projectId).digest("hex").slice(0, 16);
11338
11674
  }
11339
11675
  function validateUnderRoot(root, candidate) {
11340
11676
  const resolved = path10.resolve(candidate);
@@ -11398,7 +11734,7 @@ async function destinationExists(destination) {
11398
11734
  async function persistBuffer(bytes, destination) {
11399
11735
  await mkdir3(path10.dirname(destination), { recursive: true });
11400
11736
  if (await destinationExists(destination)) return false;
11401
- const temporary = `${destination}.${randomUUID6()}.tmp`;
11737
+ const temporary = `${destination}.${randomUUID7()}.tmp`;
11402
11738
  try {
11403
11739
  await writeFile3(temporary, bytes, { flag: "wx" });
11404
11740
  await rename2(temporary, destination);
@@ -11443,7 +11779,7 @@ async function importMediaBuffer(input) {
11443
11779
  if (input.bytes.length === 0) throw new Error("Media import rejects empty payloads");
11444
11780
  if (input.bytes.length > maxBytes) throw new Error(`Media payload is too large (${input.bytes.length} bytes; limit ${maxBytes})`);
11445
11781
  const detected = detectMedia(input.bytes.subarray(0, 32));
11446
- const sha256 = createHash5("sha256").update(input.bytes).digest("hex");
11782
+ const sha256 = createHash6("sha256").update(input.bytes).digest("hex");
11447
11783
  return importKnownMedia({
11448
11784
  dataDir: input.dataDir,
11449
11785
  projectId: input.projectId,
@@ -11461,7 +11797,7 @@ async function readMediaAsset(dataDir, asset, maxBytes = DEFAULT_MAX_MEDIA_BYTES
11461
11797
  if (asset.byteSize > maxBytes) throw new Error(`Media asset exceeds read limit (${asset.byteSize} bytes; limit ${maxBytes})`);
11462
11798
  const bytes = await readFile3(getMediaAssetPath(dataDir, asset));
11463
11799
  if (bytes.length !== asset.byteSize) throw new Error(`Media asset size no longer matches metadata: ${asset.id}`);
11464
- const sha256 = createHash5("sha256").update(bytes).digest("hex");
11800
+ const sha256 = createHash6("sha256").update(bytes).digest("hex");
11465
11801
  if (sha256 !== asset.sha256) throw new Error(`Media asset hash no longer matches metadata: ${asset.id}`);
11466
11802
  return bytes;
11467
11803
  }
@@ -64212,7 +64548,7 @@ var require_gaxios = __commonJS({
64212
64548
  var retry_js_1 = require_retry3();
64213
64549
  var stream_1 = __require("stream");
64214
64550
  var interceptor_js_1 = require_interceptor();
64215
- var randomUUID14 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
64551
+ var randomUUID16 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
64216
64552
  var HTTP_STATUS_NO_CONTENT = 204;
64217
64553
  var Gaxios = class {
64218
64554
  agentCache = /* @__PURE__ */ new Map();
@@ -64485,7 +64821,7 @@ var require_gaxios = __commonJS({
64485
64821
  */
64486
64822
  ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
64487
64823
  if (opts.multipart?.length) {
64488
- const boundary = await randomUUID14();
64824
+ const boundary = await randomUUID16();
64489
64825
  preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
64490
64826
  opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
64491
64827
  } else if (shouldDirectlyPassData) {
@@ -76712,7 +77048,7 @@ var require_websocket = __commonJS({
76712
77048
  var http3 = __require("http");
76713
77049
  var net = __require("net");
76714
77050
  var tls = __require("tls");
76715
- var { randomBytes, createHash: createHash13 } = __require("crypto");
77051
+ var { randomBytes, createHash: createHash14 } = __require("crypto");
76716
77052
  var { Duplex, Readable: Readable2 } = __require("stream");
76717
77053
  var { URL: URL2 } = __require("url");
76718
77054
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -77380,7 +77716,7 @@ var require_websocket = __commonJS({
77380
77716
  abortHandshake(websocket, socket, "Invalid Upgrade header");
77381
77717
  return;
77382
77718
  }
77383
- const digest2 = createHash13("sha1").update(key + GUID).digest("base64");
77719
+ const digest2 = createHash14("sha1").update(key + GUID).digest("base64");
77384
77720
  if (res.headers["sec-websocket-accept"] !== digest2) {
77385
77721
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
77386
77722
  return;
@@ -77752,7 +78088,7 @@ var require_websocket_server = __commonJS({
77752
78088
  var EventEmitter = __require("events");
77753
78089
  var http3 = __require("http");
77754
78090
  var { Duplex } = __require("stream");
77755
- var { createHash: createHash13 } = __require("crypto");
78091
+ var { createHash: createHash14 } = __require("crypto");
77756
78092
  var extension3 = require_extension();
77757
78093
  var PerMessageDeflate2 = require_permessage_deflate();
77758
78094
  var subprotocol2 = require_subprotocol();
@@ -78059,7 +78395,7 @@ var require_websocket_server = __commonJS({
78059
78395
  );
78060
78396
  }
78061
78397
  if (this._state > RUNNING) return abortHandshake(socket, 503);
78062
- const digest2 = createHash13("sha1").update(key + GUID).digest("base64");
78398
+ const digest2 = createHash14("sha1").update(key + GUID).digest("base64");
78063
78399
  const headers = [
78064
78400
  "HTTP/1.1 101 Switching Protocols",
78065
78401
  "Upgrade: websocket",
@@ -145197,6 +145533,186 @@ var init_audio_jobs = __esm({
145197
145533
  }
145198
145534
  });
145199
145535
 
145536
+ // src/memory/feedback-model.ts
145537
+ function feedbackWeightMultiplier(weight) {
145538
+ return Math.max(0.35, Math.min(1.4, 0.35 + Math.max(0, Math.min(2, weight)) * 0.525));
145539
+ }
145540
+ var init_feedback_model = __esm({
145541
+ "src/memory/feedback-model.ts"() {
145542
+ "use strict";
145543
+ init_esm_shims();
145544
+ }
145545
+ });
145546
+
145547
+ // src/memory/feedback.ts
145548
+ var feedback_exports = {};
145549
+ __export(feedback_exports, {
145550
+ FEEDBACK_DELTAS: () => FEEDBACK_DELTAS,
145551
+ MemoryFeedbackStore: () => MemoryFeedbackStore,
145552
+ applyMemoryFeedback: () => applyMemoryFeedback,
145553
+ feedbackWeightMultiplier: () => feedbackWeightMultiplier
145554
+ });
145555
+ import { randomUUID as randomUUID8 } from "crypto";
145556
+ function applyMemoryFeedback(current, event) {
145557
+ const delta = event.signal === "revoke" ? 0 : FEEDBACK_DELTAS[event.signal];
145558
+ const weight = Math.max(0, Math.min(2, current.weight + delta));
145559
+ const status = (event.signal === "code-conflict" || event.signal === "user-correction" || event.signal === "weaken") && weight < 0.5 ? "archived" : current.status;
145560
+ return { weight, status, audit: [...current.audit, { ...event }] };
145561
+ }
145562
+ function rowToEvent(row) {
145563
+ return {
145564
+ id: String(row.id),
145565
+ projectId: String(row.project_id),
145566
+ candidateKind: row.candidate_kind,
145567
+ candidateId: String(row.candidate_id),
145568
+ signal: row.signal,
145569
+ ...row.observed_at ? { at: String(row.observed_at) } : { at: (/* @__PURE__ */ new Date()).toISOString() },
145570
+ ...row.actor ? { actor: String(row.actor) } : {},
145571
+ ...row.note ? { note: String(row.note) } : {},
145572
+ ...row.source_ref ? { sourceRef: String(row.source_ref) } : {},
145573
+ ...row.target_event_id ? { targetEventId: String(row.target_event_id) } : {},
145574
+ delta: Number(row.delta ?? 0)
145575
+ };
145576
+ }
145577
+ var FEEDBACK_DELTAS, MemoryFeedbackStore;
145578
+ var init_feedback = __esm({
145579
+ "src/memory/feedback.ts"() {
145580
+ "use strict";
145581
+ init_esm_shims();
145582
+ init_sqlite_db();
145583
+ init_feedback_model();
145584
+ FEEDBACK_DELTAS = {
145585
+ "user-correction": -0.35,
145586
+ "verification-success": 0.25,
145587
+ "verification-failure": -0.25,
145588
+ "code-change": -0.15,
145589
+ used: 0.1,
145590
+ "not-used": -0.05,
145591
+ "code-conflict": -0.4,
145592
+ strengthen: 0.2,
145593
+ weaken: -0.2
145594
+ };
145595
+ MemoryFeedbackStore = class {
145596
+ db = null;
145597
+ async init(dataDir) {
145598
+ this.db = getDatabase(dataDir);
145599
+ }
145600
+ requireDb() {
145601
+ if (!this.db) throw new Error("MemoryFeedbackStore is not initialized.");
145602
+ return this.db;
145603
+ }
145604
+ loadEvents(projectId, candidateKind, candidateId) {
145605
+ return this.requireDb().prepare(`
145606
+ SELECT * FROM memory_feedback_events
145607
+ WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
145608
+ ORDER BY observed_at ASC, rowid ASC
145609
+ `).all(projectId, candidateKind, candidateId).map(rowToEvent);
145610
+ }
145611
+ rebuild(projectId, candidateKind, candidateId) {
145612
+ const events = this.loadEvents(projectId, candidateKind, candidateId);
145613
+ const revoked = new Set(events.filter((event) => event.signal === "revoke" && event.targetEventId).map((event) => event.targetEventId));
145614
+ let state = { weight: 1, status: "active", audit: [] };
145615
+ for (const event of events) {
145616
+ if (event.signal === "revoke" || revoked.has(event.id)) {
145617
+ state.audit.push(event);
145618
+ continue;
145619
+ }
145620
+ state = applyMemoryFeedback(state, event);
145621
+ }
145622
+ this.requireDb().prepare(`
145623
+ INSERT INTO memory_feedback_states (project_id, candidate_kind, candidate_id, weight, lifecycle_status, updated_at)
145624
+ VALUES (?, ?, ?, ?, ?, ?)
145625
+ ON CONFLICT(project_id, candidate_kind, candidate_id) DO UPDATE SET
145626
+ weight = excluded.weight, lifecycle_status = excluded.lifecycle_status, updated_at = excluded.updated_at
145627
+ `).run(projectId, candidateKind, candidateId, state.weight, state.status, (/* @__PURE__ */ new Date()).toISOString());
145628
+ return state;
145629
+ }
145630
+ getState(projectId, candidateKind, candidateId) {
145631
+ const row = this.requireDb().prepare(`
145632
+ SELECT weight, lifecycle_status FROM memory_feedback_states
145633
+ WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
145634
+ `).get(projectId, candidateKind, candidateId);
145635
+ if (!row) return { weight: 1, status: "active", audit: [] };
145636
+ return {
145637
+ weight: Number(row.weight ?? 1),
145638
+ status: row.lifecycle_status ?? "active",
145639
+ audit: this.loadEvents(projectId, candidateKind, candidateId)
145640
+ };
145641
+ }
145642
+ listStates(projectId, candidateKind = "observation") {
145643
+ return this.requireDb().prepare(`
145644
+ SELECT candidate_id, weight, lifecycle_status, updated_at
145645
+ FROM memory_feedback_states WHERE project_id = ? AND candidate_kind = ?
145646
+ ORDER BY updated_at DESC
145647
+ `).all(projectId, candidateKind).map((row) => ({
145648
+ candidateId: String(row.candidate_id),
145649
+ weight: Number(row.weight),
145650
+ status: row.lifecycle_status,
145651
+ updatedAt: String(row.updated_at)
145652
+ }));
145653
+ }
145654
+ weights(projectId, candidateKind = "observation") {
145655
+ const states = /* @__PURE__ */ new Map();
145656
+ for (const row of this.listStates(projectId, candidateKind)) {
145657
+ states.set(row.candidateId, this.getState(projectId, candidateKind, row.candidateId));
145658
+ }
145659
+ return states;
145660
+ }
145661
+ record(input) {
145662
+ if (input.signal === "revoke" && !input.targetEventId) {
145663
+ throw new Error("A revoke feedback event requires targetEventId.");
145664
+ }
145665
+ if (input.signal === "revoke") {
145666
+ const target = this.requireDb().prepare(`
145667
+ SELECT 1 FROM memory_feedback_events
145668
+ WHERE id = ? AND project_id = ? AND candidate_kind = ? AND candidate_id = ?
145669
+ `).get(input.targetEventId, input.projectId, input.candidateKind, input.candidateId);
145670
+ if (!target) throw new Error("The feedback event to revoke was not found in the same candidate scope.");
145671
+ }
145672
+ const event = {
145673
+ id: randomUUID8(),
145674
+ projectId: input.projectId,
145675
+ candidateKind: input.candidateKind,
145676
+ candidateId: input.candidateId,
145677
+ signal: input.signal,
145678
+ sourceRef: input.sourceRef,
145679
+ ...input.actor ? { actor: input.actor } : {},
145680
+ ...input.note ? { note: input.note.slice(0, 2e3) } : {},
145681
+ ...input.targetEventId ? { targetEventId: input.targetEventId } : {},
145682
+ at: input.at ?? (/* @__PURE__ */ new Date()).toISOString(),
145683
+ delta: input.signal === "revoke" ? 0 : FEEDBACK_DELTAS[input.signal]
145684
+ };
145685
+ this.requireDb().prepare(`
145686
+ INSERT INTO memory_feedback_events (
145687
+ id, project_id, candidate_kind, candidate_id, signal, actor, note,
145688
+ source_ref, target_event_id, delta, observed_at
145689
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
145690
+ `).run(
145691
+ event.id,
145692
+ event.projectId,
145693
+ event.candidateKind,
145694
+ event.candidateId,
145695
+ event.signal,
145696
+ event.actor ?? null,
145697
+ event.note ?? null,
145698
+ event.sourceRef,
145699
+ event.targetEventId ?? null,
145700
+ event.delta,
145701
+ event.at
145702
+ );
145703
+ return { event, state: this.rebuild(input.projectId, input.candidateKind, input.candidateId) };
145704
+ }
145705
+ audit(projectId, candidateKind, candidateId, limit2 = 100) {
145706
+ return this.requireDb().prepare(`
145707
+ SELECT * FROM memory_feedback_events
145708
+ WHERE project_id = ? AND candidate_kind = ? AND candidate_id = ?
145709
+ ORDER BY observed_at DESC, rowid DESC LIMIT ?
145710
+ `).all(projectId, candidateKind, candidateId, Math.min(200, Math.max(1, Math.floor(limit2)))).map(rowToEvent);
145711
+ }
145712
+ };
145713
+ }
145714
+ });
145715
+
145200
145716
  // src/memory/retention.ts
145201
145717
  var retention_exports = {};
145202
145718
  __export(retention_exports, {
@@ -145238,6 +145754,7 @@ function getEffectiveRetentionDays(doc) {
145238
145754
  }
145239
145755
  function isImmune(doc) {
145240
145756
  if (doc.type === "probe") return false;
145757
+ if (doc.feedbackStatus === "archived") return false;
145241
145758
  if (doc.admissionState === "candidate" || doc.admissionState === "ephemeral") return false;
145242
145759
  if (doc.valueCategory === "core") return true;
145243
145760
  const importance = getImportanceLevel(doc);
@@ -145270,7 +145787,8 @@ function calculateRelevance(doc, referenceTime) {
145270
145787
  const decayFactor = Math.exp(-ageDays / retention);
145271
145788
  const accessCount = doc.accessCount ?? 0;
145272
145789
  const accessBoost = Math.min(2, 1 + 0.1 * accessCount);
145273
- let totalScore = base * decayFactor * accessBoost;
145790
+ const feedbackMultiplier = doc.feedbackWeight === void 0 ? 1 : feedbackWeightMultiplier(doc.feedbackWeight);
145791
+ let totalScore = base * decayFactor * accessBoost * feedbackMultiplier;
145274
145792
  const immune = isImmune(doc);
145275
145793
  if (immune) {
145276
145794
  totalScore = Math.max(totalScore, 0.5);
@@ -145282,7 +145800,8 @@ function calculateRelevance(doc, referenceTime) {
145282
145800
  decayFactor,
145283
145801
  accessBoost,
145284
145802
  ageDays,
145285
- isImmune: immune
145803
+ isImmune: immune,
145804
+ feedbackMultiplier
145286
145805
  };
145287
145806
  }
145288
145807
  function rankByRelevance(docs, referenceTime) {
@@ -145290,6 +145809,7 @@ function rankByRelevance(docs, referenceTime) {
145290
145809
  }
145291
145810
  function getRetentionZone(doc, referenceTime) {
145292
145811
  const now3 = referenceTime ?? /* @__PURE__ */ new Date();
145812
+ if (doc.feedbackStatus === "archived") return "archive-candidate";
145293
145813
  const importance = getImportanceLevel(doc);
145294
145814
  const retention = getEffectiveRetentionDays(doc);
145295
145815
  const createdAt = new Date(doc.createdAt);
@@ -145361,7 +145881,7 @@ function explainRetention(doc, referenceTime) {
145361
145881
  summary: parts.join(" ; ")
145362
145882
  };
145363
145883
  }
145364
- function toRetentionDocument(obs, accessMap) {
145884
+ function toRetentionDocument(obs, accessMap, feedback) {
145365
145885
  const access2 = accessMap?.get(obs.id);
145366
145886
  return {
145367
145887
  id: `obs-${obs.id}`,
@@ -145383,11 +145903,12 @@ function toRetentionDocument(obs, accessMap) {
145383
145903
  sourceDetail: obs.sourceDetail ?? "",
145384
145904
  valueCategory: obs.valueCategory ?? "",
145385
145905
  admissionState: obs.admissionState ?? "",
145386
- admissionReason: obs.admissionReason ?? ""
145906
+ admissionReason: obs.admissionReason ?? "",
145907
+ ...feedback ? { feedbackWeight: feedback.weight, feedbackStatus: feedback.status } : {}
145387
145908
  };
145388
145909
  }
145389
145910
  function projectObservationRetention(observation, options = {}) {
145390
- const document2 = toRetentionDocument(observation, options.accessMap);
145911
+ const document2 = toRetentionDocument(observation, options.accessMap, options.feedback);
145391
145912
  const relevance = calculateRelevance(document2, options.referenceTime);
145392
145913
  const explanation = explainRetention(document2, options.referenceTime);
145393
145914
  return {
@@ -145412,7 +145933,17 @@ function summarizeRetentionProjections(projections) {
145412
145933
  }
145413
145934
  return { active, stale, archiveCandidates, immune };
145414
145935
  }
145415
- async function archiveExpiredBatch(_projectDir, options) {
145936
+ async function loadFeedbackStore(dataDir) {
145937
+ try {
145938
+ const { MemoryFeedbackStore: MemoryFeedbackStore2 } = await Promise.resolve().then(() => (init_feedback(), feedback_exports));
145939
+ const store = new MemoryFeedbackStore2();
145940
+ await store.init(dataDir);
145941
+ return store;
145942
+ } catch {
145943
+ return void 0;
145944
+ }
145945
+ }
145946
+ async function archiveExpiredBatch(projectDir2, options) {
145416
145947
  const store = getObservationStore();
145417
145948
  const limit2 = Math.min(500, Math.max(1, Math.floor(options.limit ?? 100)));
145418
145949
  const afterId = Math.max(0, Math.floor(options.afterId ?? 0));
@@ -145421,11 +145952,13 @@ async function archiveExpiredBatch(_projectDir, options) {
145421
145952
  afterId,
145422
145953
  limit: limit2 + 1
145423
145954
  });
145955
+ const feedback = await loadFeedbackStore(projectDir2);
145424
145956
  const hasMore = page.length > limit2;
145425
145957
  const scanned = hasMore ? page.slice(0, limit2) : page;
145426
145958
  const candidateIds = scanned.filter((observation) => !options.reader || canManageObservation(observation, options.reader)).filter((observation) => projectObservationRetention(observation, {
145427
145959
  accessMap: options.accessMap,
145428
- referenceTime: options.referenceTime
145960
+ referenceTime: options.referenceTime,
145961
+ ...feedback ? { feedback: feedback.getState(options.projectId, "observation", String(observation.id)) } : {}
145429
145962
  }).zone === "archive-candidate").map((observation) => observation.id);
145430
145963
  const archived = candidateIds.length === 0 ? 0 : await store.atomic(async (tx) => {
145431
145964
  const updates = await Promise.all(
@@ -145456,6 +145989,7 @@ async function archiveExpired(projectDir2, referenceTime, accessMap, projectId,
145456
145989
  const remaining = reader ? remainingObservations.filter((observation) => canManageObservation(observation, reader)).length : remainingObservations.length;
145457
145990
  return { archived, remaining };
145458
145991
  }
145992
+ const feedback = await loadFeedbackStore(projectDir2);
145459
145993
  return await store.atomic(async (tx) => {
145460
145994
  const allObs = await tx.loadAll();
145461
145995
  const activeObs = allObs.filter(
@@ -145463,7 +145997,11 @@ async function archiveExpired(projectDir2, referenceTime, accessMap, projectId,
145463
145997
  );
145464
145998
  const archivedIds = [];
145465
145999
  for (const obs of activeObs) {
145466
- const retention = projectObservationRetention(obs, { accessMap, referenceTime });
146000
+ const retention = projectObservationRetention(obs, {
146001
+ accessMap,
146002
+ referenceTime,
146003
+ ...feedback ? { feedback: feedback.getState(obs.projectId, "observation", String(obs.id)) } : {}
146004
+ });
145467
146005
  if (retention.zone === "archive-candidate") {
145468
146006
  archivedIds.push(obs.id);
145469
146007
  }
@@ -145483,6 +146021,7 @@ var init_retention = __esm({
145483
146021
  init_esm_shims();
145484
146022
  init_obs_store();
145485
146023
  init_visibility();
146024
+ init_feedback_model();
145486
146025
  RETENTION_DAYS = {
145487
146026
  critical: 365,
145488
146027
  high: 180,
@@ -145519,7 +146058,7 @@ var init_retention = __esm({
145519
146058
  });
145520
146059
 
145521
146060
  // src/memory/owner.ts
145522
- import { randomUUID as randomUUID7 } from "crypto";
146061
+ import { randomUUID as randomUUID9 } from "crypto";
145523
146062
  import { promises as fs9 } from "fs";
145524
146063
  import path16 from "path";
145525
146064
  function ownerPath(dataDir) {
@@ -145549,7 +146088,7 @@ async function resolveLocalMemoryOwner(dataDir, options = {}) {
145549
146088
  await fs9.mkdir(path16.dirname(filePath), { recursive: true });
145550
146089
  const created = {
145551
146090
  version: 1,
145552
- id: "local-" + randomUUID7(),
146091
+ id: "local-" + randomUUID9(),
145553
146092
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
145554
146093
  };
145555
146094
  try {
@@ -145572,7 +146111,7 @@ var init_owner = __esm({
145572
146111
  });
145573
146112
 
145574
146113
  // src/memory/long-term-store.ts
145575
- import { randomUUID as randomUUID8 } from "crypto";
146114
+ import { randomUUID as randomUUID10 } from "crypto";
145576
146115
  function optionalText2(value) {
145577
146116
  return typeof value === "string" && value.trim() ? value : void 0;
145578
146117
  }
@@ -145623,7 +146162,7 @@ function rowToEvidence(row) {
145623
146162
  createdAt: row.createdAt
145624
146163
  };
145625
146164
  }
145626
- function rowToEvent(row) {
146165
+ function rowToEvent2(row) {
145627
146166
  return {
145628
146167
  id: row.id,
145629
146168
  memoryId: row.memoryId,
@@ -145732,7 +146271,7 @@ var init_long_term_store = __esm({
145732
146271
  }
145733
146272
  insertEvidence(input) {
145734
146273
  const evidence = {
145735
- id: randomUUID8(),
146274
+ id: randomUUID10(),
145736
146275
  ...input,
145737
146276
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
145738
146277
  };
@@ -145759,7 +146298,7 @@ var init_long_term_store = __esm({
145759
146298
  }
145760
146299
  recordEvent(input) {
145761
146300
  const event = {
145762
- id: randomUUID8(),
146301
+ id: randomUUID10(),
145763
146302
  ...input,
145764
146303
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
145765
146304
  };
@@ -145780,7 +146319,7 @@ var init_long_term_store = __esm({
145780
146319
  listEvents(memoryId) {
145781
146320
  return this.db.prepare(`
145782
146321
  SELECT * FROM long_term_memory_events WHERE memoryId = ? ORDER BY createdAt ASC, rowid ASC
145783
- `).all(memoryId).map(rowToEvent);
146322
+ `).all(memoryId).map(rowToEvent2);
145784
146323
  }
145785
146324
  markAccess(ids, at = (/* @__PURE__ */ new Date()).toISOString()) {
145786
146325
  const unique = [...new Set(ids.filter(Boolean))];
@@ -145849,7 +146388,7 @@ __export(long_term_exports, {
145849
146388
  selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
145850
146389
  supersedeLongTermMemory: () => supersedeLongTermMemory
145851
146390
  });
145852
- import { randomUUID as randomUUID9 } from "crypto";
146391
+ import { randomUUID as randomUUID11 } from "crypto";
145853
146392
  function isOneOf(value, values) {
145854
146393
  return typeof value === "string" && values.includes(value);
145855
146394
  }
@@ -146031,7 +146570,7 @@ async function createManualLongTermMemory(input) {
146031
146570
  const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
146032
146571
  if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
146033
146572
  assertScope(input.scope);
146034
- const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID9(), relation: "supports" }];
146573
+ const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID11(), relation: "supports" }];
146035
146574
  return createLongTermMemoryWithDataDir({
146036
146575
  dataDir: input.dataDir,
146037
146576
  originProjectId: input.projectId,
@@ -146086,7 +146625,7 @@ async function createLongTermMemoryWithDataDir(input) {
146086
146625
  assertPortableEvidence(input.scope, portability, evidenceInputs);
146087
146626
  const now3 = (/* @__PURE__ */ new Date()).toISOString();
146088
146627
  const memory = {
146089
- id: randomUUID9(),
146628
+ id: randomUUID11(),
146090
146629
  originProjectId: compactText(input.originProjectId, "origin project id", 1e3),
146091
146630
  ownerId: compactText(input.ownerId, "owner id", 160),
146092
146631
  scope: input.scope,
@@ -146405,7 +146944,7 @@ var init_long_term = __esm({
146405
146944
 
146406
146945
  // src/codegraph/code-state.ts
146407
146946
  import { execFile as execFile2 } from "child_process";
146408
- import { createHash as createHash6 } from "crypto";
146947
+ import { createHash as createHash7 } from "crypto";
146409
146948
  import { promisify as promisify3 } from "util";
146410
146949
  async function runGit(rootPath, args) {
146411
146950
  try {
@@ -146434,7 +146973,7 @@ function changedPathCount(status) {
146434
146973
  return count2;
146435
146974
  }
146436
146975
  function fingerprint(baseRevision, status) {
146437
- return createHash6("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146976
+ return createHash7("sha256").update(baseRevision ?? "").update("\0").update(status).digest("hex");
146438
146977
  }
146439
146978
  async function collectCodeStateSnapshot(input) {
146440
146979
  const [revision, status] = await Promise.all([
@@ -146534,11 +147073,11 @@ __export(lite_provider_exports, {
146534
147073
  indexProjectLite: () => indexProjectLite,
146535
147074
  refreshProjectLite: () => refreshProjectLite
146536
147075
  });
146537
- import { createHash as createHash7 } from "crypto";
147076
+ import { createHash as createHash8 } from "crypto";
146538
147077
  import { readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync3 } from "fs";
146539
147078
  import { join as join4, relative } from "path";
146540
147079
  function hashText(text2) {
146541
- return createHash7("sha256").update(text2).digest("hex");
147080
+ return createHash8("sha256").update(text2).digest("hex");
146542
147081
  }
146543
147082
  function extension2(path21) {
146544
147083
  const index = path21.lastIndexOf(".");
@@ -146948,7 +147487,7 @@ var claim_store_exports = {};
146948
147487
  __export(claim_store_exports, {
146949
147488
  ClaimStore: () => ClaimStore
146950
147489
  });
146951
- import { createHash as createHash8, randomUUID as randomUUID10 } from "crypto";
147490
+ import { createHash as createHash9, randomUUID as randomUUID12 } from "crypto";
146952
147491
  function optionalText3(value) {
146953
147492
  return typeof value === "string" && value ? value : void 0;
146954
147493
  }
@@ -146987,7 +147526,7 @@ function rowToEvidence2(row) {
146987
147526
  createdAt: row.createdAt
146988
147527
  };
146989
147528
  }
146990
- function rowToEvent2(row) {
147529
+ function rowToEvent3(row) {
146991
147530
  return {
146992
147531
  id: row.id,
146993
147532
  projectId: row.projectId,
@@ -147001,7 +147540,7 @@ function rowToEvent2(row) {
147001
147540
  };
147002
147541
  }
147003
147542
  function evidenceKey(input) {
147004
- return createHash8("sha256").update(JSON.stringify([
147543
+ return createHash9("sha256").update(JSON.stringify([
147005
147544
  input.evidenceKind,
147006
147545
  input.evidenceId,
147007
147546
  input.relation,
@@ -147132,7 +147671,7 @@ var init_claim_store = __esm({
147132
147671
  locator, capturedHash, evidenceKey, createdAt
147133
147672
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
147134
147673
  `).run(
147135
- randomUUID10(),
147674
+ randomUUID12(),
147136
147675
  input.claimId,
147137
147676
  input.evidenceKind,
147138
147677
  input.evidenceId,
@@ -147154,7 +147693,7 @@ var init_claim_store = __esm({
147154
147693
  }
147155
147694
  recordEvent(input) {
147156
147695
  const event = {
147157
- id: randomUUID10(),
147696
+ id: randomUUID12(),
147158
147697
  ...input,
147159
147698
  ...input.detail ? { detail: sanitizeCredentials(input.detail) } : {},
147160
147699
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
@@ -147182,7 +147721,7 @@ var init_claim_store = __esm({
147182
147721
  SELECT * FROM knowledge_claim_events
147183
147722
  WHERE claimId = ?
147184
147723
  ORDER BY createdAt ASC, id
147185
- `).all(claimId).map(rowToEvent2);
147724
+ `).all(claimId).map(rowToEvent3);
147186
147725
  }
147187
147726
  };
147188
147727
  }
@@ -147199,7 +147738,7 @@ __export(claims_exports, {
147199
147738
  supersedeClaim: () => supersedeClaim,
147200
147739
  writeClaim: () => writeClaim
147201
147740
  });
147202
- import { createHash as createHash9, randomUUID as randomUUID11 } from "crypto";
147741
+ import { createHash as createHash10, randomUUID as randomUUID13 } from "crypto";
147203
147742
  function compactText2(value, field) {
147204
147743
  if (typeof value !== "string") throw new Error("Claim " + field + " must be text");
147205
147744
  const sanitized = sanitizeCredentials(value).trim().replace(/\s+/g, " ");
@@ -147211,7 +147750,7 @@ function normalizedTerm(value) {
147211
147750
  return compactText2(value, "identity").toLocaleLowerCase("en-US");
147212
147751
  }
147213
147752
  function hashIdentity(parts) {
147214
- return createHash9("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
147753
+ return createHash10("sha256").update(parts.join(String.fromCharCode(31))).digest("hex");
147215
147754
  }
147216
147755
  function buildClaimIdentity(input) {
147217
147756
  const subject = normalizedTerm(input.subject);
@@ -147285,7 +147824,7 @@ function normalizeClaimInput(input) {
147285
147824
  const now3 = (/* @__PURE__ */ new Date()).toISOString();
147286
147825
  return {
147287
147826
  claim: {
147288
- id: randomUUID11(),
147827
+ id: randomUUID13(),
147289
147828
  projectId,
147290
147829
  subject,
147291
147830
  predicate,
@@ -147452,7 +147991,7 @@ function supersedeClaim(store, input) {
147452
147991
  });
147453
147992
  }
147454
147993
  function hashObservation(observation) {
147455
- return createHash9("sha256").update(JSON.stringify([
147994
+ return createHash10("sha256").update(JSON.stringify([
147456
147995
  observation.title,
147457
147996
  observation.narrative,
147458
147997
  observation.facts,
@@ -147696,11 +148235,11 @@ var init_frontmatter = __esm({
147696
148235
  });
147697
148236
 
147698
148237
  // src/knowledge/markdown.ts
147699
- import { createHash as createHash10 } from "crypto";
148238
+ import { createHash as createHash11 } from "crypto";
147700
148239
  import { promises as fs10 } from "fs";
147701
148240
  import path17 from "path";
147702
148241
  function hashContent(content) {
147703
- return createHash10("sha256").update(content).digest("hex");
148242
+ return createHash11("sha256").update(content).digest("hex");
147704
148243
  }
147705
148244
  function stringField(data, key) {
147706
148245
  const value = data[key];
@@ -147826,11 +148365,11 @@ __export(wiki_exports, {
147826
148365
  lintKnowledgeWorkspace: () => lintKnowledgeWorkspace,
147827
148366
  readKnowledgePage: () => readKnowledgePage
147828
148367
  });
147829
- import { createHash as createHash11 } from "crypto";
148368
+ import { createHash as createHash12 } from "crypto";
147830
148369
  import { promises as fs11 } from "fs";
147831
148370
  import path18 from "path";
147832
148371
  function hash2(value) {
147833
- return createHash11("sha256").update(value).digest("hex");
148372
+ return createHash12("sha256").update(value).digest("hex");
147834
148373
  }
147835
148374
  function now() {
147836
148375
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -148370,7 +148909,7 @@ var init_workflow_sync = __esm({
148370
148909
  });
148371
148910
 
148372
148911
  // src/knowledge/workflow-store.ts
148373
- import { randomUUID as randomUUID12 } from "crypto";
148912
+ import { randomUUID as randomUUID14 } from "crypto";
148374
148913
  function parseJson(value, fallback) {
148375
148914
  if (typeof value !== "string" || !value) return fallback;
148376
148915
  try {
@@ -148470,7 +149009,7 @@ var init_workflow_store = __esm({
148470
149009
  }
148471
149010
  recordRun(input) {
148472
149011
  const run = {
148473
- id: randomUUID12(),
149012
+ id: randomUUID14(),
148474
149013
  workflowId: input.workflowId,
148475
149014
  projectId: input.projectId,
148476
149015
  task: input.task.trim(),
@@ -148538,7 +149077,7 @@ var init_outcome_types = __esm({
148538
149077
  });
148539
149078
 
148540
149079
  // src/knowledge/outcome-store.ts
148541
- import { randomUUID as randomUUID13 } from "crypto";
149080
+ import { randomUUID as randomUUID15 } from "crypto";
148542
149081
  function optionalText5(value) {
148543
149082
  return typeof value === "string" && value.trim() ? value : void 0;
148544
149083
  }
@@ -148582,7 +149121,7 @@ var init_outcome_store = __esm({
148582
149121
  }
148583
149122
  record(input) {
148584
149123
  const signal = {
148585
- id: randomUUID13(),
149124
+ id: randomUUID15(),
148586
149125
  projectId: text(input.projectId, "project id"),
148587
149126
  candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
148588
149127
  candidateId: text(input.candidateId, "candidate id"),
@@ -148687,11 +149226,11 @@ __export(workflows_exports, {
148687
149226
  syncCanonicalWorkflows: () => syncCanonicalWorkflows,
148688
149227
  writeCanonicalWorkflow: () => writeCanonicalWorkflow
148689
149228
  });
148690
- import { createHash as createHash12 } from "crypto";
149229
+ import { createHash as createHash13 } from "crypto";
148691
149230
  import { promises as fs12 } from "fs";
148692
149231
  import path19 from "path";
148693
149232
  function hash3(value) {
148694
- return createHash12("sha256").update(value).digest("hex");
149233
+ return createHash13("sha256").update(value).digest("hex");
148695
149234
  }
148696
149235
  function now2() {
148697
149236
  return (/* @__PURE__ */ new Date()).toISOString();