memorix 1.4.0 → 1.4.2

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 (38) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/CLAUDE.md +9 -9
  3. package/README.md +7 -2
  4. package/README.zh-CN.md +6 -2
  5. package/dist/cli/index.js +1216 -485
  6. package/dist/index.js +984 -337
  7. package/dist/maintenance-runner.js +564 -180
  8. package/dist/media-video-runner.js +564 -180
  9. package/dist/memcode/index.js +53 -21
  10. package/dist/memcode-runtime/CHANGELOG.md +31 -0
  11. package/dist/sdk.js +983 -336
  12. package/dist/vector-backfill-runner.js +564 -180
  13. package/docs/1.4.2-EVIDENCE-GOVERNED-MEMORY-SPEC.md +434 -0
  14. package/docs/API_REFERENCE.md +1 -1
  15. package/docs/KNOWN_ISSUES_AND_ROADMAP.md +52 -128
  16. package/package.json +5 -2
  17. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  18. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  19. package/plugins/copilot/memorix/plugin.json +1 -1
  20. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  21. package/plugins/omp/memorix/package.json +1 -1
  22. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  23. package/plugins/pi/memorix/package.json +1 -1
  24. package/server.json +2 -2
  25. package/src/cli/commands/codegraph.ts +83 -2
  26. package/src/codegraph/auto-context.ts +20 -0
  27. package/src/codegraph/current-facts.ts +1 -0
  28. package/src/codegraph/external-provider.ts +1 -0
  29. package/src/codegraph/store.ts +216 -5
  30. package/src/codegraph/types.ts +42 -0
  31. package/src/knowledge/context-assembly.ts +25 -0
  32. package/src/knowledge/governor.ts +156 -0
  33. package/src/knowledge/outcome-store.ts +102 -0
  34. package/src/knowledge/outcome-types.ts +49 -0
  35. package/src/knowledge/workflows.ts +32 -1
  36. package/src/knowledge/workset.ts +203 -13
  37. package/src/store/sqlite-db.ts +42 -0
  38. package/docs/dev-log/progress.txt +0 -388
package/dist/sdk.js CHANGED
@@ -363,7 +363,7 @@ function closeAllDatabases() {
363
363
  _dbCache.delete(key);
364
364
  }
365
365
  }
366
- var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_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;
366
+ 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;
367
367
  var init_sqlite_db = __esm({
368
368
  "src/store/sqlite-db.ts"() {
369
369
  "use strict";
@@ -629,6 +629,17 @@ CREATE TABLE IF NOT EXISTS observation_code_refs (
629
629
  " UNIQUE(projectId, sourceEpoch)",
630
630
  ");"
631
631
  ].join("\n");
632
+ CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE = [
633
+ "CREATE TABLE IF NOT EXISTS code_state_snapshot_files (",
634
+ " snapshotId TEXT NOT NULL,",
635
+ " projectId TEXT NOT NULL,",
636
+ " fileId TEXT NOT NULL,",
637
+ " path TEXT NOT NULL,",
638
+ " contentHash TEXT NOT NULL,",
639
+ " PRIMARY KEY (snapshotId, path),",
640
+ " FOREIGN KEY (snapshotId) REFERENCES code_state_snapshots(id) ON DELETE CASCADE",
641
+ ");"
642
+ ].join("\n");
632
643
  CREATE_KNOWLEDGE_CLAIMS_TABLE = `
633
644
  CREATE TABLE IF NOT EXISTS knowledge_claims (
634
645
  id TEXT PRIMARY KEY,
@@ -839,6 +850,19 @@ CREATE TABLE IF NOT EXISTS long_term_memory_events (
839
850
  createdAt TEXT NOT NULL,
840
851
  FOREIGN KEY (memoryId) REFERENCES long_term_memories(id) ON DELETE CASCADE
841
852
  );
853
+ `;
854
+ CREATE_MEMORY_OUTCOME_SIGNALS_TABLE = `
855
+ CREATE TABLE IF NOT EXISTS memory_outcome_signals (
856
+ id TEXT PRIMARY KEY,
857
+ projectId TEXT NOT NULL,
858
+ candidateKind TEXT NOT NULL,
859
+ candidateId TEXT NOT NULL,
860
+ kind TEXT NOT NULL,
861
+ sourceRef TEXT NOT NULL,
862
+ snapshotId TEXT,
863
+ detail TEXT,
864
+ observedAt TEXT NOT NULL
865
+ );
842
866
  `;
843
867
  CREATE_MEDIA_ASSETS_TABLE = `
844
868
  CREATE TABLE IF NOT EXISTS media_assets (
@@ -1081,6 +1105,20 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1081
1105
  db2.exec("CREATE INDEX IF NOT EXISTS idx_code_edges_snapshot ON code_edges(projectId, snapshotId)");
1082
1106
  }
1083
1107
  },
1108
+ {
1109
+ id: "1.4-codegraph-snapshot-manifest",
1110
+ apply: (db2) => {
1111
+ db2.exec(CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE);
1112
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_code_snapshot_files_project_path ON code_state_snapshot_files(projectId, path)");
1113
+ }
1114
+ },
1115
+ {
1116
+ id: "1.4-memory-outcome-signals",
1117
+ apply: (db2) => {
1118
+ db2.exec(CREATE_MEMORY_OUTCOME_SIGNALS_TABLE);
1119
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_outcomes_candidate ON memory_outcome_signals(projectId, candidateKind, candidateId, observedAt DESC)");
1120
+ }
1121
+ },
1084
1122
  {
1085
1123
  id: "1.2-knowledge-claim-ledger",
1086
1124
  apply: (db2) => {
@@ -2280,17 +2318,17 @@ var init_mini_skill_store = __esm({
2280
2318
 
2281
2319
  // src/compact/token-budget.ts
2282
2320
  import { countTokens, isWithinTokenLimit } from "gpt-tokenizer";
2283
- function countTextTokens(text) {
2284
- return countTokens(text);
2321
+ function countTextTokens(text2) {
2322
+ return countTokens(text2);
2285
2323
  }
2286
- function fitsInBudget(text, limit2) {
2287
- return isWithinTokenLimit(text, limit2);
2324
+ function fitsInBudget(text2, limit2) {
2325
+ return isWithinTokenLimit(text2, limit2);
2288
2326
  }
2289
- function truncateToTokenBudget(text, budget) {
2290
- if (fitsInBudget(text, budget) !== false) {
2291
- return text;
2327
+ function truncateToTokenBudget(text2, budget) {
2328
+ if (fitsInBudget(text2, budget) !== false) {
2329
+ return text2;
2292
2330
  }
2293
- const sentences = text.split(/(?<=[.!?])\s+/);
2331
+ const sentences = text2.split(/(?<=[.!?])\s+/);
2294
2332
  let result = "";
2295
2333
  for (const sentence of sentences) {
2296
2334
  const candidate = result ? `${result} ${sentence}` : sentence;
@@ -2301,12 +2339,12 @@ function truncateToTokenBudget(text, budget) {
2301
2339
  }
2302
2340
  if (!result) {
2303
2341
  const estimatedChars = budget * 2;
2304
- result = text.slice(0, estimatedChars);
2342
+ result = text2.slice(0, estimatedChars);
2305
2343
  while (fitsInBudget(result, budget) === false && result.length > 0) {
2306
2344
  result = result.slice(0, Math.floor(result.length * 0.9));
2307
2345
  }
2308
- if (result.length < text.length) {
2309
- const nextCharacter = text.charAt(result.length);
2346
+ if (result.length < text2.length) {
2347
+ const nextCharacter = text2.charAt(result.length);
2310
2348
  if (nextCharacter && !/[\s.,;:!?)}\]]/.test(nextCharacter)) {
2311
2349
  const boundary = result.search(/\s+\S*$/);
2312
2350
  result = boundary > 0 ? result.slice(0, boundary).trimEnd() : "";
@@ -3438,8 +3476,8 @@ import { createHash } from "crypto";
3438
3476
  import { readFile, writeFile, mkdir } from "fs/promises";
3439
3477
  import { join as join2 } from "path";
3440
3478
  import { homedir as homedir6 } from "os";
3441
- function textHash(text) {
3442
- return createHash("sha256").update(text).digest("hex").slice(0, 16);
3479
+ function textHash(text2) {
3480
+ return createHash("sha256").update(text2).digest("hex").slice(0, 16);
3443
3481
  }
3444
3482
  async function loadDiskCache() {
3445
3483
  try {
@@ -3502,11 +3540,11 @@ var init_fastembed_provider = __esm({
3502
3540
  async embedInputs(inputs, options = {}) {
3503
3541
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
3504
3542
  }
3505
- async embed(text) {
3506
- const hash4 = textHash(text);
3543
+ async embed(text2) {
3544
+ const hash4 = textHash(text2);
3507
3545
  const cached = cache.get(hash4);
3508
3546
  if (cached) return cached;
3509
- const raw = await this.model.queryEmbed(text);
3547
+ const raw = await this.model.queryEmbed(text2);
3510
3548
  const result = Array.from(raw);
3511
3549
  if (result.length !== this.dimensions) {
3512
3550
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
@@ -3602,10 +3640,10 @@ var init_transformers_provider = __esm({
3602
3640
  async embedInputs(inputs, options = {}) {
3603
3641
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
3604
3642
  }
3605
- async embed(text) {
3606
- const cached = cache2.get(text);
3643
+ async embed(text2) {
3644
+ const cached = cache2.get(text2);
3607
3645
  if (cached) return cached;
3608
- const output = await this.extractor(text, {
3646
+ const output = await this.extractor(text2, {
3609
3647
  pooling: "mean",
3610
3648
  normalize: true
3611
3649
  });
@@ -3613,7 +3651,7 @@ var init_transformers_provider = __esm({
3613
3651
  if (result.length !== this.dimensions) {
3614
3652
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
3615
3653
  }
3616
- this.cacheSet(text, result);
3654
+ this.cacheSet(text2, result);
3617
3655
  return result;
3618
3656
  }
3619
3657
  async embedBatch(texts) {
@@ -3676,8 +3714,8 @@ function dimsCacheFile() {
3676
3714
  function cacheMetaFile() {
3677
3715
  return join3(cacheDir(), ".embedding-api-cache-meta.json");
3678
3716
  }
3679
- function normalizeText(text) {
3680
- return text.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
3717
+ function normalizeText(text2) {
3718
+ return text2.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
3681
3719
  }
3682
3720
  function cacheNamespace(config) {
3683
3721
  return [
@@ -3687,8 +3725,8 @@ function cacheNamespace(config) {
3687
3725
  config.requestedDimensions ?? "native"
3688
3726
  ].join("|");
3689
3727
  }
3690
- function textHash2(text, namespace) {
3691
- return createHash2("sha256").update(`${namespace}\0${text}`).digest("hex").slice(0, 16);
3728
+ function textHash2(text2, namespace) {
3729
+ return createHash2("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
3692
3730
  }
3693
3731
  function inputIdentity(input, options = {}) {
3694
3732
  return JSON.stringify({
@@ -4100,8 +4138,8 @@ var init_api_provider = __esm({
4100
4138
  if (!embedding) throw new Error("API probe returned no embeddings; check model name and API key");
4101
4139
  return embedding.length;
4102
4140
  }
4103
- async embed(text, options) {
4104
- const normalized = normalizeText(text);
4141
+ async embed(text2, options) {
4142
+ const normalized = normalizeText(text2);
4105
4143
  if (isNativeGeminiEndpoint(this.config.baseUrl)) {
4106
4144
  return this.embedInput({ modality: "text", text: normalized }, { intent: "document", ...options });
4107
4145
  }
@@ -4158,7 +4196,7 @@ var init_api_provider = __esm({
4158
4196
  }
4159
4197
  async embedBatch(texts, options) {
4160
4198
  if (isNativeGeminiEndpoint(this.config.baseUrl)) {
4161
- return Promise.all(texts.map((text) => this.embedInput({ modality: "text", text }, { intent: "document", ...options })));
4199
+ return Promise.all(texts.map((text2) => this.embedInput({ modality: "text", text: text2 }, { intent: "document", ...options })));
4162
4200
  }
4163
4201
  await ensureDiskCacheLoaded();
4164
4202
  const normalizedTexts = texts.map(normalizeText);
@@ -4237,8 +4275,8 @@ var init_api_provider = __esm({
4237
4275
  }
4238
4276
  async getCachedEmbeddings(texts) {
4239
4277
  await ensureDiskCacheLoaded();
4240
- return texts.map((text) => {
4241
- const hash4 = textHash2(normalizeText(text), this.cacheKeyNamespace);
4278
+ return texts.map((text2) => {
4279
+ const hash4 = textHash2(normalizeText(text2), this.cacheKeyNamespace);
4242
4280
  return cache3.get(hash4) ?? null;
4243
4281
  });
4244
4282
  }
@@ -4468,9 +4506,9 @@ function wrapProvider(candidate) {
4468
4506
  return {
4469
4507
  name: candidate.name,
4470
4508
  dimensions: candidate.dimensions,
4471
- async embed(text, options) {
4509
+ async embed(text2, options) {
4472
4510
  try {
4473
- return await candidate.embed(text, options);
4511
+ return await candidate.embed(text2, options);
4474
4512
  } catch (error) {
4475
4513
  if (kind === "api" && getEmbeddingMode2() === "auto" && isTemporaryEmbeddingFailure(error)) {
4476
4514
  warnOnce("[memorix] API embedding temporarily unavailable \u2014 switching to local fallback provider");
@@ -4478,7 +4516,7 @@ function wrapProvider(candidate) {
4478
4516
  if (fallback) {
4479
4517
  provider = wrapProvider(fallback);
4480
4518
  warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);
4481
- return provider.embed(text, options);
4519
+ return provider.embed(text2, options);
4482
4520
  }
4483
4521
  }
4484
4522
  if (isTemporaryEmbeddingFailure(error)) {
@@ -5037,8 +5075,8 @@ async function readResponseText(response, signal, maxBytes = MAX_LLM_RESPONSE_BY
5037
5075
  }
5038
5076
  }
5039
5077
  async function readResponseJson(response, signal, maxBytes = MAX_LLM_RESPONSE_BYTES) {
5040
- const text = await readResponseText(response, signal, maxBytes);
5041
- return JSON.parse(text);
5078
+ const text2 = await readResponseText(response, signal, maxBytes);
5079
+ return JSON.parse(text2);
5042
5080
  }
5043
5081
  async function* callLLMWithToolsStream(messages, tools) {
5044
5082
  if (!currentConfig) {
@@ -5591,8 +5629,8 @@ function isCjkHeavy(query) {
5591
5629
  const cjkCount = (query.match(CJK_PATTERN) || []).length;
5592
5630
  return query.length > 0 && cjkCount / query.length > 0.3;
5593
5631
  }
5594
- function normalizeExpansion(text) {
5595
- return text.trim().replace(/^[-*]\s*/, "").replace(/^["'`]+|["'`]+$/g, "").split(/\r?\n/)[0].trim();
5632
+ function normalizeExpansion(text2) {
5633
+ return text2.trim().replace(/^[-*]\s*/, "").replace(/^["'`]+|["'`]+$/g, "").split(/\r?\n/)[0].trim();
5596
5634
  }
5597
5635
  async function maybeExpandSearchQuery(query) {
5598
5636
  if (!query || !isCjkHeavy(query) || COMMAND_LIKE_QUERY.test(query)) {
@@ -5955,9 +5993,9 @@ function shouldSkipCompression(narrative, type) {
5955
5993
  if (specialChars / narrative.length > 0.35) return true;
5956
5994
  return false;
5957
5995
  }
5958
- function estimateTokens(text) {
5959
- const cjkChars = (text.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length;
5960
- const otherChars = text.length - cjkChars;
5996
+ function estimateTokens(text2) {
5997
+ const cjkChars = (text2.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length;
5998
+ const otherChars = text2.length - cjkChars;
5961
5999
  return Math.ceil(cjkChars / 1.5 + otherChars / 4);
5962
6000
  }
5963
6001
  var COMPRESS_PROMPT, COMPRESS_PROMPT_GENTLE, RERANK_PROMPT, SKIP_PATTERNS, LOW_COMPRESSION_TYPES;
@@ -6260,10 +6298,10 @@ function isEmbeddingEnabled() {
6260
6298
  function getVectorDimensions() {
6261
6299
  return embeddingEnabled ? embeddingDimensions : null;
6262
6300
  }
6263
- async function generateEmbedding(text) {
6301
+ async function generateEmbedding(text2) {
6264
6302
  const provider2 = await getEmbeddingProvider();
6265
6303
  if (!provider2) return null;
6266
- return provider2.embedInput ? provider2.embedInput({ modality: "text", text }, { intent: "document" }) : provider2.embed(text);
6304
+ return provider2.embedInput ? provider2.embedInput({ modality: "text", text: text2 }, { intent: "document" }) : provider2.embed(text2);
6267
6305
  }
6268
6306
  async function generateEmbeddingInput(input, options = {}) {
6269
6307
  const provider2 = await getEmbeddingProvider();
@@ -7595,9 +7633,9 @@ var init_entity_extractor = __esm({
7595
7633
  });
7596
7634
 
7597
7635
  // src/memory/secret-filter.ts
7598
- function applyRedaction(text) {
7599
- if (!text) return text;
7600
- let out = text;
7636
+ function applyRedaction(text2) {
7637
+ if (!text2) return text2;
7638
+ let out = text2;
7601
7639
  out = out.replace(
7602
7640
  /((?:password|passwd|pwd|secret|token|api[_-]?key|auth[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret)\s*[:=]\s*["']?)([^\s"',;\n]{6,})/gi,
7603
7641
  "$1[REDACTED]"
@@ -7611,11 +7649,11 @@ function applyRedaction(text) {
7611
7649
  out = out.replace(/\beyJ[A-Za-z0-9._-]{40,}\b/g, "[REDACTED]");
7612
7650
  return out;
7613
7651
  }
7614
- function sanitizeCredentials(text) {
7615
- return applyRedaction(text);
7652
+ function sanitizeCredentials(text2) {
7653
+ return applyRedaction(text2);
7616
7654
  }
7617
- function redactCredentials(text) {
7618
- return applyRedaction(text);
7655
+ function redactCredentials(text2) {
7656
+ return applyRedaction(text2);
7619
7657
  }
7620
7658
  var init_secret_filter = __esm({
7621
7659
  "src/memory/secret-filter.ts"() {
@@ -7666,8 +7704,8 @@ function clampPositiveInteger(value, fallback) {
7666
7704
  return Math.max(1, Math.floor(value));
7667
7705
  }
7668
7706
  function errorText(error) {
7669
- const text = error instanceof Error ? error.message : String(error);
7670
- return sanitizeCredentials(text).slice(0, MAX_ERROR_LENGTH);
7707
+ const text2 = error instanceof Error ? error.message : String(error);
7708
+ return sanitizeCredentials(text2).slice(0, MAX_ERROR_LENGTH);
7671
7709
  }
7672
7710
  function normalizedKinds(kinds) {
7673
7711
  if (!kinds) return void 0;
@@ -8761,9 +8799,9 @@ __export(consolidation_exports, {
8761
8799
  executeConsolidation: () => executeConsolidation,
8762
8800
  findConsolidationCandidates: () => findConsolidationCandidates
8763
8801
  });
8764
- function tokenize(text) {
8802
+ function tokenize(text2) {
8765
8803
  return new Set(
8766
- text.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff\s-]/g, " ").split(/\s+/).filter((t2) => t2.length > 1)
8804
+ text2.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff\s-]/g, " ").split(/\s+/).filter((t2) => t2.length > 1)
8767
8805
  );
8768
8806
  }
8769
8807
  function jaccardSimilarity(a, b) {
@@ -17915,8 +17953,8 @@ var init_headers = __esm({
17915
17953
  });
17916
17954
 
17917
17955
  // packages/ai/dist/utils/sanitize-unicode.js
17918
- function sanitizeSurrogates(text) {
17919
- return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
17956
+ function sanitizeSurrogates(text2) {
17957
+ return text2.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
17920
17958
  }
17921
17959
  var init_sanitize_unicode = __esm({
17922
17960
  "packages/ai/dist/utils/sanitize-unicode.js"() {
@@ -18398,9 +18436,9 @@ var init_values = __esm({
18398
18436
  }
18399
18437
  return n;
18400
18438
  };
18401
- safeJSON = (text) => {
18439
+ safeJSON = (text2) => {
18402
18440
  try {
18403
- return JSON.parse(text);
18441
+ return JSON.parse(text2);
18404
18442
  } catch (err) {
18405
18443
  return void 0;
18406
18444
  }
@@ -19563,8 +19601,8 @@ async function defaultParseResponse(client, props) {
19563
19601
  const json2 = await response.json();
19564
19602
  return addRequestID(json2, response);
19565
19603
  }
19566
- const text = await response.text();
19567
- return text;
19604
+ const text2 = await response.text();
19605
+ return text2;
19568
19606
  })();
19569
19607
  loggerFor(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails({
19570
19608
  retryOfRequestLogID,
@@ -32934,7 +32972,7 @@ var init_models_generated = __esm({
32934
32972
  provider: "minimax",
32935
32973
  baseUrl: "https://api.minimax.io/anthropic",
32936
32974
  reasoning: true,
32937
- input: ["text", "image"],
32975
+ input: ["text", "image", "video"],
32938
32976
  cost: {
32939
32977
  input: 0.3,
32940
32978
  output: 1.2,
@@ -32987,7 +33025,7 @@ var init_models_generated = __esm({
32987
33025
  provider: "minimax-cn",
32988
33026
  baseUrl: "https://api.minimaxi.com/anthropic",
32989
33027
  reasoning: true,
32990
- input: ["text", "image"],
33028
+ input: ["text", "image", "video"],
32991
33029
  cost: {
32992
33030
  input: 0.3,
32993
33031
  output: 1.2,
@@ -45182,9 +45220,9 @@ var init_values2 = __esm({
45182
45220
  }
45183
45221
  return n;
45184
45222
  };
45185
- safeJSON2 = (text) => {
45223
+ safeJSON2 = (text2) => {
45186
45224
  try {
45187
- return JSON.parse(text);
45225
+ return JSON.parse(text2);
45188
45226
  } catch (err) {
45189
45227
  return void 0;
45190
45228
  }
@@ -45958,8 +45996,8 @@ async function defaultParseResponse2(client, props) {
45958
45996
  const json2 = await response.json();
45959
45997
  return addRequestID2(json2, response);
45960
45998
  }
45961
- const text = await response.text();
45962
- return text;
45999
+ const text2 = await response.text();
46000
+ return text2;
45963
46001
  })();
45964
46002
  loggerFor2(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails2({
45965
46003
  retryOfRequestLogID,
@@ -52262,11 +52300,11 @@ var init_simple_options = __esm({
52262
52300
  });
52263
52301
 
52264
52302
  // packages/ai/dist/providers/transform-messages.js
52265
- function replaceImagesWithPlaceholder(content, placeholder) {
52303
+ function replaceMediaWithPlaceholder(content, dropType, placeholder) {
52266
52304
  const result = [];
52267
52305
  let previousWasPlaceholder = false;
52268
52306
  for (const block of content) {
52269
- if (block.type === "image") {
52307
+ if (block.type === dropType) {
52270
52308
  if (!previousWasPlaceholder) {
52271
52309
  result.push({ type: "text", text: placeholder });
52272
52310
  }
@@ -52274,33 +52312,39 @@ function replaceImagesWithPlaceholder(content, placeholder) {
52274
52312
  continue;
52275
52313
  }
52276
52314
  result.push(block);
52277
- previousWasPlaceholder = block.text === placeholder;
52315
+ previousWasPlaceholder = block.type === "text" && block.text === placeholder;
52278
52316
  }
52279
52317
  return result;
52280
52318
  }
52281
- function downgradeUnsupportedImages(messages, model) {
52282
- if (model.input.includes("image")) {
52319
+ function downgradeUnsupportedMedia(messages, model) {
52320
+ const supportsImage = model.input.includes("image");
52321
+ const supportsVideo = model.input.includes("video");
52322
+ if (supportsImage && supportsVideo) {
52283
52323
  return messages;
52284
52324
  }
52285
52325
  return messages.map((msg) => {
52286
52326
  if (msg.role === "user" && Array.isArray(msg.content)) {
52287
- return {
52288
- ...msg,
52289
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER)
52290
- };
52327
+ let content = msg.content;
52328
+ if (!supportsImage)
52329
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_USER_IMAGE_PLACEHOLDER);
52330
+ if (!supportsVideo)
52331
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_USER_VIDEO_PLACEHOLDER);
52332
+ return { ...msg, content };
52291
52333
  }
52292
52334
  if (msg.role === "toolResult") {
52293
- return {
52294
- ...msg,
52295
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)
52296
- };
52335
+ let content = msg.content;
52336
+ if (!supportsImage)
52337
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_TOOL_IMAGE_PLACEHOLDER);
52338
+ if (!supportsVideo)
52339
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_TOOL_VIDEO_PLACEHOLDER);
52340
+ return { ...msg, content };
52297
52341
  }
52298
52342
  return msg;
52299
52343
  });
52300
52344
  }
52301
52345
  function transformMessages(messages, model, normalizeToolCallId2) {
52302
52346
  const toolCallIdMap = /* @__PURE__ */ new Map();
52303
- const imageAwareMessages = downgradeUnsupportedImages(messages, model);
52347
+ const imageAwareMessages = downgradeUnsupportedMedia(messages, model);
52304
52348
  const transformed = imageAwareMessages.map((msg) => {
52305
52349
  if (msg.role === "user") {
52306
52350
  return msg;
@@ -52412,13 +52456,15 @@ function transformMessages(messages, model, normalizeToolCallId2) {
52412
52456
  insertSyntheticToolResults();
52413
52457
  return result;
52414
52458
  }
52415
- var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER;
52459
+ var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER, NON_VISION_USER_VIDEO_PLACEHOLDER, NON_VISION_TOOL_VIDEO_PLACEHOLDER;
52416
52460
  var init_transform_messages = __esm({
52417
52461
  "packages/ai/dist/providers/transform-messages.js"() {
52418
52462
  "use strict";
52419
52463
  init_esm_shims();
52420
52464
  NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
52421
52465
  NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
52466
+ NON_VISION_USER_VIDEO_PLACEHOLDER = "(video omitted: model does not support video)";
52467
+ NON_VISION_TOOL_VIDEO_PLACEHOLDER = "(tool video omitted: model does not support video)";
52422
52468
  }
52423
52469
  });
52424
52470
 
@@ -52449,8 +52495,8 @@ function getCacheControl(model, cacheRetention) {
52449
52495
  };
52450
52496
  }
52451
52497
  function convertContentBlocks(content) {
52452
- const hasImages = content.some((c) => c.type === "image");
52453
- if (!hasImages) {
52498
+ const hasMedia = content.some((c) => c.type === "image" || c.type === "video");
52499
+ if (!hasMedia) {
52454
52500
  return sanitizeSurrogates(content.map((c) => c.text).join("\n"));
52455
52501
  }
52456
52502
  const blocks = content.map((block) => {
@@ -52460,6 +52506,16 @@ function convertContentBlocks(content) {
52460
52506
  text: sanitizeSurrogates(block.text)
52461
52507
  };
52462
52508
  }
52509
+ if (block.type === "video") {
52510
+ return {
52511
+ type: "video",
52512
+ source: {
52513
+ type: "base64",
52514
+ media_type: block.mimeType,
52515
+ data: block.data
52516
+ }
52517
+ };
52518
+ }
52463
52519
  return {
52464
52520
  type: "image",
52465
52521
  source: {
@@ -52473,7 +52529,7 @@ function convertContentBlocks(content) {
52473
52529
  if (!hasText) {
52474
52530
  blocks.unshift({
52475
52531
  type: "text",
52476
- text: "(see attached image)"
52532
+ text: "(see attached media)"
52477
52533
  });
52478
52534
  }
52479
52535
  return blocks;
@@ -52534,9 +52590,9 @@ function decodeSseLine(line, state) {
52534
52590
  }
52535
52591
  return null;
52536
52592
  }
52537
- function nextLineBreakIndex(text) {
52538
- const carriageReturnIndex = text.indexOf("\r");
52539
- const newlineIndex = text.indexOf("\n");
52593
+ function nextLineBreakIndex(text2) {
52594
+ const carriageReturnIndex = text2.indexOf("\r");
52595
+ const newlineIndex = text2.indexOf("\n");
52540
52596
  if (carriageReturnIndex === -1) {
52541
52597
  return newlineIndex;
52542
52598
  }
@@ -52545,18 +52601,18 @@ function nextLineBreakIndex(text) {
52545
52601
  }
52546
52602
  return Math.min(carriageReturnIndex, newlineIndex);
52547
52603
  }
52548
- function consumeLine(text) {
52549
- const lineBreakIndex = nextLineBreakIndex(text);
52604
+ function consumeLine(text2) {
52605
+ const lineBreakIndex = nextLineBreakIndex(text2);
52550
52606
  if (lineBreakIndex === -1) {
52551
52607
  return null;
52552
52608
  }
52553
52609
  let nextIndex = lineBreakIndex + 1;
52554
- if (text[lineBreakIndex] === "\r" && text[nextIndex] === "\n") {
52610
+ if (text2[lineBreakIndex] === "\r" && text2[nextIndex] === "\n") {
52555
52611
  nextIndex += 1;
52556
52612
  }
52557
52613
  return {
52558
- line: text.slice(0, lineBreakIndex),
52559
- rest: text.slice(nextIndex)
52614
+ line: text2.slice(0, lineBreakIndex),
52615
+ rest: text2.slice(nextIndex)
52560
52616
  };
52561
52617
  }
52562
52618
  async function* iterateSseMessages(body, signal) {
@@ -52823,6 +52879,15 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
52823
52879
  type: "text",
52824
52880
  text: sanitizeSurrogates(item.text)
52825
52881
  };
52882
+ } else if (item.type === "video") {
52883
+ return {
52884
+ type: "video",
52885
+ source: {
52886
+ type: "base64",
52887
+ media_type: item.mimeType,
52888
+ data: item.data
52889
+ }
52890
+ };
52826
52891
  } else {
52827
52892
  return {
52828
52893
  type: "image",
@@ -52903,6 +52968,8 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
52903
52968
  toolResults.push({
52904
52969
  type: "tool_result",
52905
52970
  tool_use_id: msg.toolCallId,
52971
+ // MiniMax's Anthropic-compatible API accepts video in tool results;
52972
+ // the SDK's ToolResultBlockParam.content type predates video support.
52906
52973
  content: convertContentBlocks(msg.content),
52907
52974
  is_error: msg.isError
52908
52975
  });
@@ -52929,7 +52996,7 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
52929
52996
  if (lastMessage.role === "user") {
52930
52997
  if (Array.isArray(lastMessage.content)) {
52931
52998
  const lastBlock = lastMessage.content[lastMessage.content.length - 1];
52932
- if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "tool_result")) {
52999
+ if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "video" || lastBlock.type === "tool_result")) {
52933
53000
  lastBlock.cache_control = cacheControl;
52934
53001
  }
52935
53002
  } else if (typeof lastMessage.content === "string") {
@@ -54712,8 +54779,8 @@ var require_common = __commonJS({
54712
54779
  }
54713
54780
  function redactString(obj, key) {
54714
54781
  if (typeof obj === "object" && obj !== null && typeof obj[key] === "string") {
54715
- const text = obj[key];
54716
- if (/grant_type=/i.test(text) || /assertion=/i.test(text) || /secret/i.test(text)) {
54782
+ const text2 = obj[key];
54783
+ if (/grant_type=/i.test(text2) || /assertion=/i.test(text2) || /secret/i.test(text2)) {
54717
54784
  obj[key] = REDACT;
54718
54785
  }
54719
54786
  }
@@ -61541,8 +61608,8 @@ var init_body = __esm({
61541
61608
  * @return Promise
61542
61609
  */
61543
61610
  async json() {
61544
- const text = await this.text();
61545
- return JSON.parse(text);
61611
+ const text2 = await this.text();
61612
+ return JSON.parse(text2);
61546
61613
  }
61547
61614
  /**
61548
61615
  * Decode response as text
@@ -62694,7 +62761,7 @@ var require_gaxios = __commonJS({
62694
62761
  var retry_js_1 = require_retry3();
62695
62762
  var stream_1 = __require("stream");
62696
62763
  var interceptor_js_1 = require_interceptor();
62697
- var randomUUID16 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
62764
+ var randomUUID17 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
62698
62765
  var HTTP_STATUS_NO_CONTENT = 204;
62699
62766
  var Gaxios = class {
62700
62767
  agentCache = /* @__PURE__ */ new Map();
@@ -62967,7 +63034,7 @@ var require_gaxios = __commonJS({
62967
63034
  */
62968
63035
  ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
62969
63036
  if (opts.multipart?.length) {
62970
- const boundary = await randomUUID16();
63037
+ const boundary = await randomUUID17();
62971
63038
  preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
62972
63039
  opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
62973
63040
  } else if (shouldDirectlyPassData) {
@@ -64718,18 +64785,18 @@ var require_parse = __commonJS({
64718
64785
  n: "\n",
64719
64786
  r: "\r",
64720
64787
  t: " "
64721
- }, text, error = function(m2) {
64788
+ }, text2, error = function(m2) {
64722
64789
  throw {
64723
64790
  name: "SyntaxError",
64724
64791
  message: m2,
64725
64792
  at,
64726
- text
64793
+ text: text2
64727
64794
  };
64728
64795
  }, next = function(c) {
64729
64796
  if (c && c !== ch) {
64730
64797
  error("Expected '" + c + "' instead of '" + ch + "'");
64731
64798
  }
64732
- ch = text.charAt(at);
64799
+ ch = text2.charAt(at);
64733
64800
  at += 1;
64734
64801
  return ch;
64735
64802
  }, number44 = function() {
@@ -64776,12 +64843,12 @@ var require_parse = __commonJS({
64776
64843
  var startAt = at;
64777
64844
  while (next()) {
64778
64845
  if (ch === '"') {
64779
- if (at - 1 > startAt) string474 += text.substring(startAt, at - 1);
64846
+ if (at - 1 > startAt) string474 += text2.substring(startAt, at - 1);
64780
64847
  next();
64781
64848
  return string474;
64782
64849
  }
64783
64850
  if (ch === "\\") {
64784
- if (at - 1 > startAt) string474 += text.substring(startAt, at - 1);
64851
+ if (at - 1 > startAt) string474 += text2.substring(startAt, at - 1);
64785
64852
  next();
64786
64853
  if (ch === "u") {
64787
64854
  uffff = 0;
@@ -64914,7 +64981,7 @@ var require_parse = __commonJS({
64914
64981
  };
64915
64982
  return function(source, reviver) {
64916
64983
  var result;
64917
- text = source + "";
64984
+ text2 = source + "";
64918
64985
  at = 0;
64919
64986
  ch = " ";
64920
64987
  result = value();
@@ -65826,8 +65893,8 @@ var require_crypto = __commonJS({
65826
65893
  const result = new TextDecoder().decode(uint8array);
65827
65894
  return result;
65828
65895
  }
65829
- encodeBase64StringUtf8(text) {
65830
- const uint8array = new TextEncoder().encode(text);
65896
+ encodeBase64StringUtf8(text2) {
65897
+ const uint8array = new TextEncoder().encode(text2);
65831
65898
  const result = base64js.fromByteArray(uint8array);
65832
65899
  return result;
65833
65900
  }
@@ -65896,8 +65963,8 @@ var require_crypto2 = __commonJS({
65896
65963
  decodeBase64StringUtf8(base64) {
65897
65964
  return Buffer.from(base64, "base64").toString("utf-8");
65898
65965
  }
65899
- encodeBase64StringUtf8(text) {
65900
- return Buffer.from(text, "utf-8").toString("base64");
65966
+ encodeBase64StringUtf8(text2) {
65967
+ return Buffer.from(text2, "utf-8").toString("base64");
65901
65968
  }
65902
65969
  /**
65903
65970
  * Computes the SHA-256 hash of the provided string.
@@ -86342,8 +86409,8 @@ async function defaultParseResponse3(client, props) {
86342
86409
  const json2 = await response.json();
86343
86410
  return json2;
86344
86411
  }
86345
- const text = await response.text();
86346
- return text;
86412
+ const text2 = await response.text();
86413
+ return text2;
86347
86414
  })();
86348
86415
  loggerFor3(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails3({
86349
86416
  retryOfRequestLogID,
@@ -87920,7 +87987,7 @@ var init_node = __esm({
87920
87987
  if (this.candidates && this.candidates.length > 1) {
87921
87988
  console.warn("there are multiple candidates in the response, returning text from the first one.");
87922
87989
  }
87923
- let text = "";
87990
+ let text2 = "";
87924
87991
  let anyTextPartText = false;
87925
87992
  const nonTextParts = [];
87926
87993
  for (const part of (_h = (_g = (_f = (_e = this.candidates) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.content) === null || _g === void 0 ? void 0 : _g.parts) !== null && _h !== void 0 ? _h : []) {
@@ -87934,13 +88001,13 @@ var init_node = __esm({
87934
88001
  continue;
87935
88002
  }
87936
88003
  anyTextPartText = true;
87937
- text += part.text;
88004
+ text2 += part.text;
87938
88005
  }
87939
88006
  }
87940
88007
  if (nonTextParts.length > 0) {
87941
88008
  console.warn(`there are non-text parts ${nonTextParts} in the response, returning concatenation of all text parts. Please refer to the non text parts for a full response from model.`);
87942
88009
  }
87943
- return anyTextPartText ? text : void 0;
88010
+ return anyTextPartText ? text2 : void 0;
87944
88011
  }
87945
88012
  /**
87946
88013
  * Returns the concatenation of all inline data parts from the first candidate
@@ -88193,7 +88260,7 @@ var init_node = __esm({
88193
88260
  */
88194
88261
  get text() {
88195
88262
  var _a5, _b, _c;
88196
- let text = "";
88263
+ let text2 = "";
88197
88264
  let anyTextPartFound = false;
88198
88265
  const nonTextParts = [];
88199
88266
  for (const part of (_c = (_b = (_a5 = this.serverContent) === null || _a5 === void 0 ? void 0 : _a5.modelTurn) === null || _b === void 0 ? void 0 : _b.parts) !== null && _c !== void 0 ? _c : []) {
@@ -88207,13 +88274,13 @@ var init_node = __esm({
88207
88274
  continue;
88208
88275
  }
88209
88276
  anyTextPartFound = true;
88210
- text += part.text;
88277
+ text2 += part.text;
88211
88278
  }
88212
88279
  }
88213
88280
  if (nonTextParts.length > 0) {
88214
88281
  console.warn(`there are non-text parts ${nonTextParts} in the response, returning concatenation of all text parts. Please refer to the non text parts for a full response from model.`);
88215
88282
  }
88216
- return anyTextPartFound ? text : void 0;
88283
+ return anyTextPartFound ? text2 : void 0;
88217
88284
  }
88218
88285
  /**
88219
88286
  * Returns the concatenation of all inline data parts from the server content if present.
@@ -92885,9 +92952,9 @@ var init_node = __esm({
92885
92952
  }
92886
92953
  return n;
92887
92954
  };
92888
- safeJSON3 = (text) => {
92955
+ safeJSON3 = (text2) => {
92889
92956
  try {
92890
- return JSON.parse(text);
92957
+ return JSON.parse(text2);
92891
92958
  } catch (err) {
92892
92959
  return void 0;
92893
92960
  }
@@ -110750,8 +110817,8 @@ function findBoundary(buf) {
110750
110817
  return null;
110751
110818
  }
110752
110819
  function parseMessage2(chunk, parse2, state, dataRequired) {
110753
- const text = new TextDecoder().decode(chunk);
110754
- const lines = text.split(/\r\n|\r|\n/);
110820
+ const text2 = new TextDecoder().decode(chunk);
110821
+ const lines = text2.split(/\r\n|\r|\n/);
110755
110822
  const dataLines = [];
110756
110823
  const ret = {};
110757
110824
  let ignore = true;
@@ -133625,10 +133692,10 @@ function formatMistralError(error) {
133625
133692
  }
133626
133693
  return safeJsonStringify(error);
133627
133694
  }
133628
- function truncateErrorText(text, maxChars) {
133629
- if (text.length <= maxChars)
133630
- return text;
133631
- return `${text.slice(0, maxChars)}... [truncated ${text.length - maxChars} chars]`;
133695
+ function truncateErrorText(text2, maxChars) {
133696
+ if (text2.length <= maxChars)
133697
+ return text2;
133698
+ return `${text2.slice(0, maxChars)}... [truncated ${text2.length - maxChars} chars]`;
133632
133699
  }
133633
133700
  function safeJsonStringify(value) {
133634
133701
  try {
@@ -133748,7 +133815,7 @@ async function consumeChatStream(model, output, stream2, mistralStream) {
133748
133815
  continue;
133749
133816
  }
133750
133817
  if (item.type === "thinking") {
133751
- const deltaText = item.thinking.map((part) => "text" in part ? part.text : "").filter((text) => text.length > 0).join("");
133818
+ const deltaText = item.thinking.map((part) => "text" in part ? part.text : "").filter((text2) => text2.length > 0).join("");
133752
133819
  const thinkingDelta = sanitizeSurrogates(deltaText);
133753
133820
  if (!thinkingDelta)
133754
133821
  continue;
@@ -133945,8 +134012,8 @@ function toChatMessages(messages, supportsImages) {
133945
134012
  }
133946
134013
  return result;
133947
134014
  }
133948
- function buildToolResultText(text, hasImages, supportsImages, isError) {
133949
- const trimmed = text.trim();
134015
+ function buildToolResultText(text2, hasImages, supportsImages, isError) {
134016
+ const trimmed = text2.trim();
133950
134017
  const errorPrefix = isError ? "[tool error] " : "";
133951
134018
  if (trimmed.length > 0) {
133952
134019
  const imageSuffix = hasImages && !supportsImages ? "\n[tool image omitted: model does not support images]" : "";
@@ -134747,14 +134814,14 @@ async function* parseWebSocket(socket, signal, idleTimeoutMs) {
134747
134814
  };
134748
134815
  const onMessage = (event) => {
134749
134816
  void (async () => {
134750
- let text = null;
134817
+ let text2 = null;
134751
134818
  try {
134752
134819
  if (!event || typeof event !== "object" || !("data" in event))
134753
134820
  return;
134754
- text = await decodeWebSocketData(event.data);
134755
- if (!text)
134821
+ text2 = await decodeWebSocketData(event.data);
134822
+ if (!text2)
134756
134823
  return;
134757
- const parsed = JSON.parse(text);
134824
+ const parsed = JSON.parse(text2);
134758
134825
  const type = typeof parsed.type === "string" ? parsed.type : "";
134759
134826
  if (type === "response.completed" || type === "response.done" || type === "response.incomplete") {
134760
134827
  sawCompletion = true;
@@ -134765,7 +134832,7 @@ async function* parseWebSocket(socket, signal, idleTimeoutMs) {
134765
134832
  } catch (cause) {
134766
134833
  failed = new CodexProtocolError(`Invalid Codex WebSocket JSON: ${formatThrownValue(cause)}`, {
134767
134834
  cause,
134768
- payload: text
134835
+ payload: text2
134769
134836
  });
134770
134837
  done = true;
134771
134838
  wake();
@@ -142958,11 +143025,11 @@ function videoRequestConfig(input) {
142958
143025
  };
142959
143026
  }
142960
143027
  async function readMiniMaxJson(response) {
142961
- const text = await response.text();
143028
+ const text2 = await response.text();
142962
143029
  let body = {};
142963
- if (text) {
143030
+ if (text2) {
142964
143031
  try {
142965
- const parsed = JSON.parse(text);
143032
+ const parsed = JSON.parse(text2);
142966
143033
  if (isRecord2(parsed)) body = parsed;
142967
143034
  } catch {
142968
143035
  throw new Error("MiniMax video API returned invalid JSON");
@@ -143865,6 +143932,7 @@ __export(store_exports, {
143865
143932
  CodeGraphStore: () => CodeGraphStore
143866
143933
  });
143867
143934
  import { randomUUID as randomUUID6 } from "crypto";
143935
+ import { posix as pathPosix } from "path";
143868
143936
  function rowToFile(row) {
143869
143937
  return {
143870
143938
  id: row.id,
@@ -143915,6 +143983,26 @@ function rowToEdge(row) {
143915
143983
  ...row.sourceEpoch != null ? { sourceEpoch: Number(row.sourceEpoch) } : {}
143916
143984
  };
143917
143985
  }
143986
+ function resolveRelativeImportTarget(sourcePath, evidence, fileByPath) {
143987
+ const target = evidence?.trim().replace(/\\/g, "/");
143988
+ if (!target?.startsWith(".")) return void 0;
143989
+ const base = normalizeCodePath(pathPosix.normalize(pathPosix.join(pathPosix.dirname(sourcePath), target)));
143990
+ if (!base || base === ".." || base.startsWith("../")) return void 0;
143991
+ const candidates = [base];
143992
+ const extensionMatch = base.match(/(\.[A-Za-z0-9]+)$/);
143993
+ const hasExtension = Boolean(extensionMatch);
143994
+ if (!hasExtension) {
143995
+ const extensions = [...new Set([...fileByPath.keys()].map((path33) => path33.match(/(\.[A-Za-z0-9]+)$/)?.[1]).filter((extension3) => Boolean(extension3)))];
143996
+ for (const extension3 of extensions) {
143997
+ candidates.push(`${base}${extension3}`, `${base}/index${extension3}`);
143998
+ }
143999
+ } else {
144000
+ const sourceStem = base.slice(0, -extensionMatch[1].length);
144001
+ const sourceExtensions = extensionMatch[1] === ".js" ? [".ts", ".tsx", ".js", ".jsx"] : extensionMatch[1] === ".mjs" ? [".mts", ".mjs"] : extensionMatch[1] === ".cjs" ? [".cts", ".cjs"] : [];
144002
+ for (const extension3 of sourceExtensions) candidates.push(`${sourceStem}${extension3}`);
144003
+ }
144004
+ return candidates.map((candidate) => fileByPath.get(candidate)).find((file) => Boolean(file));
144005
+ }
143918
144006
  function rowToRef(row) {
143919
144007
  return {
143920
144008
  id: row.id,
@@ -143975,6 +144063,18 @@ function rowToSnapshot(row) {
143975
144063
  ...row.previousSnapshotId ? { previousSnapshotId: row.previousSnapshotId } : {}
143976
144064
  };
143977
144065
  }
144066
+ function rowToSnapshotFile(row) {
144067
+ return {
144068
+ snapshotId: row.snapshotId,
144069
+ projectId: row.projectId,
144070
+ fileId: row.fileId,
144071
+ path: row.path,
144072
+ contentHash: row.contentHash
144073
+ };
144074
+ }
144075
+ function snapshotIsIncomplete(snapshot) {
144076
+ return snapshot.completeness.skippedOversizedFiles > 0 || (snapshot.completeness.unreadableFiles ?? 0) > 0 || snapshot.completeness.removalScanDeferred;
144077
+ }
143978
144078
  var CodeGraphStore;
143979
144079
  var init_store = __esm({
143980
144080
  "src/codegraph/store.ts"() {
@@ -144146,6 +144246,7 @@ var init_store = __esm({
144146
144246
  }
144147
144247
  });
144148
144248
  tx();
144249
+ this.reconcileLocalImportTargets(projectId);
144149
144250
  }
144150
144251
  /**
144151
144252
  * Reconcile only files whose source changed plus files that disappeared.
@@ -144155,7 +144256,10 @@ var init_store = __esm({
144155
144256
  const changed = input.changed.filter((delta) => delta.file.projectId === projectId);
144156
144257
  const metadataOnly = (input.metadataOnly ?? []).filter((file) => file.projectId === projectId);
144157
144258
  const removedFileIds = input.removedFileIds ?? [];
144158
- if (changed.length === 0 && metadataOnly.length === 0 && removedFileIds.length === 0) return;
144259
+ if (changed.length === 0 && metadataOnly.length === 0 && removedFileIds.length === 0) {
144260
+ this.reconcileLocalImportTargets(projectId);
144261
+ return;
144262
+ }
144159
144263
  const staleRefsForFile = this.db.prepare(`
144160
144264
  UPDATE observation_code_refs
144161
144265
  SET status = 'stale', updatedAt = ?
@@ -144165,9 +144269,18 @@ var init_store = __esm({
144165
144269
  )
144166
144270
  )
144167
144271
  `);
144168
- const deleteEdgesForFile = this.db.prepare(`
144272
+ const deleteEdgesFromFile = this.db.prepare(`
144273
+ DELETE FROM code_edges
144274
+ WHERE projectId = ? AND fromFileId = ?
144275
+ `);
144276
+ const clearImportTargetsForFile = this.db.prepare(`
144277
+ UPDATE code_edges
144278
+ SET toFileId = NULL
144279
+ WHERE projectId = ? AND toFileId = ? AND type = 'imports'
144280
+ `);
144281
+ const deleteOtherIncomingEdgesForFile = this.db.prepare(`
144169
144282
  DELETE FROM code_edges
144170
- WHERE projectId = ? AND (fromFileId = ? OR toFileId = ?)
144283
+ WHERE projectId = ? AND toFileId = ? AND type != 'imports'
144171
144284
  `);
144172
144285
  const deleteSymbolsForFile = this.db.prepare(`DELETE FROM code_symbols WHERE projectId = ? AND fileId = ?`);
144173
144286
  const deleteFile = this.db.prepare(`DELETE FROM code_files WHERE projectId = ? AND id = ?`);
@@ -144204,14 +144317,18 @@ var init_store = __esm({
144204
144317
  const staleAt = (/* @__PURE__ */ new Date()).toISOString();
144205
144318
  for (const fileId of removedFileIds) {
144206
144319
  staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);
144207
- deleteEdgesForFile.run(projectId, fileId, fileId);
144320
+ deleteEdgesFromFile.run(projectId, fileId);
144321
+ clearImportTargetsForFile.run(projectId, fileId);
144322
+ deleteOtherIncomingEdgesForFile.run(projectId, fileId);
144208
144323
  deleteSymbolsForFile.run(projectId, fileId);
144209
144324
  deleteFile.run(projectId, fileId);
144210
144325
  }
144211
144326
  for (const delta of changed) {
144212
144327
  const fileId = delta.file.id;
144213
144328
  staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);
144214
- deleteEdgesForFile.run(projectId, fileId, fileId);
144329
+ deleteEdgesFromFile.run(projectId, fileId);
144330
+ clearImportTargetsForFile.run(projectId, fileId);
144331
+ deleteOtherIncomingEdgesForFile.run(projectId, fileId);
144215
144332
  deleteSymbolsForFile.run(projectId, fileId);
144216
144333
  writeFile7(delta.file);
144217
144334
  for (const symbol of delta.symbols) {
@@ -144249,6 +144366,7 @@ var init_store = __esm({
144249
144366
  for (const file of metadataOnly) writeFile7(file);
144250
144367
  });
144251
144368
  tx();
144369
+ this.reconcileLocalImportTargets(projectId);
144252
144370
  }
144253
144371
  upsertObservationRefs(refs) {
144254
144372
  if (refs.length === 0) return;
@@ -144310,6 +144428,25 @@ var init_store = __esm({
144310
144428
  });
144311
144429
  tx();
144312
144430
  }
144431
+ /**
144432
+ * Lite import extraction records the original import text first. Resolve only
144433
+ * local relative imports against the current index after each refresh, so an
144434
+ * added or removed target cannot leave a fabricated file-to-file relation.
144435
+ */
144436
+ reconcileLocalImportTargets(projectId) {
144437
+ const fileById = new Map(this.listFiles(projectId).map((file) => [file.id, file]));
144438
+ const fileByPath = new Map([...fileById.values()].map((file) => [file.path, file]));
144439
+ const update2 = this.db.prepare("UPDATE code_edges SET toFileId = ? WHERE id = ?");
144440
+ const tx = this.db.transaction(() => {
144441
+ for (const edge of this.listEdges(projectId)) {
144442
+ if (edge.type !== "imports" || !edge.fromFileId) continue;
144443
+ const source = fileById.get(edge.fromFileId);
144444
+ const target = source ? resolveRelativeImportTarget(source.path, edge.evidence, fileByPath) : void 0;
144445
+ update2.run(target?.id ?? null, edge.id);
144446
+ }
144447
+ });
144448
+ tx();
144449
+ }
144313
144450
  getFile(projectId, path33) {
144314
144451
  const row = this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? AND path = ?`).get(projectId, normalizeCodePath(path33));
144315
144452
  return row ? rowToFile(row) : null;
@@ -144384,6 +144521,18 @@ var init_store = __esm({
144384
144521
  ORDER BY observationId, status, id
144385
144522
  `).all(projectId).map(rowToRef);
144386
144523
  }
144524
+ /** Count distinct observations whose binding to these exact files is stale. */
144525
+ countStaleObservationRefsForFiles(projectId, fileIds) {
144526
+ const ids = [...new Set(fileIds.filter(Boolean))];
144527
+ if (ids.length === 0) return 0;
144528
+ const placeholders = ids.map(() => "?").join(", ");
144529
+ const row = this.db.prepare(`
144530
+ SELECT COUNT(DISTINCT observationId) AS count
144531
+ FROM observation_code_refs
144532
+ WHERE projectId = ? AND status = 'stale' AND fileId IN (${placeholders})
144533
+ `).get(projectId, ...ids);
144534
+ return Number(row?.count ?? 0);
144535
+ }
144387
144536
  listReferencedSymbols(projectId) {
144388
144537
  return this.db.prepare(`
144389
144538
  SELECT DISTINCT symbols.*
@@ -144405,6 +144554,94 @@ var init_store = __esm({
144405
144554
  "SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT ?"
144406
144555
  ).all(projectId, safeLimit2).map(rowToSnapshot);
144407
144556
  }
144557
+ listSnapshotFiles(snapshotId) {
144558
+ return this.db.prepare(`
144559
+ SELECT snapshotId, projectId, fileId, path, contentHash
144560
+ FROM code_state_snapshot_files
144561
+ WHERE snapshotId = ?
144562
+ ORDER BY path
144563
+ `).all(snapshotId).map(rowToSnapshotFile);
144564
+ }
144565
+ diffSnapshots(projectId, fromSnapshotId, toSnapshotId) {
144566
+ const snapshots = this.db.prepare(`
144567
+ SELECT * FROM code_state_snapshots WHERE id IN (?, ?)
144568
+ `).all(fromSnapshotId, toSnapshotId).map(rowToSnapshot);
144569
+ if (snapshots.length !== 2) {
144570
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "missing-snapshot", changes: [] };
144571
+ }
144572
+ if (snapshots.some((snapshot) => snapshot.projectId !== projectId)) {
144573
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "project-mismatch", changes: [] };
144574
+ }
144575
+ if (snapshots.some(snapshotIsIncomplete)) {
144576
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "incomplete-snapshot", changes: [] };
144577
+ }
144578
+ const before = this.listSnapshotFiles(fromSnapshotId);
144579
+ const after = this.listSnapshotFiles(toSnapshotId);
144580
+ if (before.length === 0 || after.length === 0) {
144581
+ return {
144582
+ projectId,
144583
+ fromSnapshotId,
144584
+ toSnapshotId,
144585
+ available: false,
144586
+ reason: "legacy-snapshot-without-manifest",
144587
+ changes: []
144588
+ };
144589
+ }
144590
+ const beforeByPath = new Map(before.map((file) => [file.path, file]));
144591
+ const afterByPath = new Map(after.map((file) => [file.path, file]));
144592
+ const paths = [.../* @__PURE__ */ new Set([...beforeByPath.keys(), ...afterByPath.keys()])].sort();
144593
+ const changes = [];
144594
+ for (const path33 of paths) {
144595
+ const oldFile = beforeByPath.get(path33);
144596
+ const newFile = afterByPath.get(path33);
144597
+ if (!oldFile && newFile) {
144598
+ changes.push({ path: path33, kind: "added", afterHash: newFile.contentHash });
144599
+ } else if (oldFile && !newFile) {
144600
+ changes.push({ path: path33, kind: "removed", beforeHash: oldFile.contentHash });
144601
+ } else if (oldFile && newFile && oldFile.contentHash !== newFile.contentHash) {
144602
+ changes.push({ path: path33, kind: "modified", beforeHash: oldFile.contentHash, afterHash: newFile.contentHash });
144603
+ }
144604
+ }
144605
+ return { projectId, fromSnapshotId, toSnapshotId, available: true, changes };
144606
+ }
144607
+ impactSlice(projectId, changedPaths, maxRelations = 24) {
144608
+ const safeLimit2 = Number.isFinite(maxRelations) ? Math.max(1, Math.min(100, Math.floor(maxRelations))) : 24;
144609
+ const normalizedPaths = [...new Set(changedPaths.map(normalizeCodePath).filter(Boolean))].sort();
144610
+ const files = this.listFiles(projectId);
144611
+ const fileById = new Map(files.map((file) => [file.id, file.path]));
144612
+ const fileIdBySymbolId = new Map(this.listSymbols(projectId).map((symbol) => [symbol.id, symbol.fileId]));
144613
+ const changedIds = new Set(files.filter((file) => normalizedPaths.includes(file.path)).map((file) => file.id));
144614
+ const direct = /* @__PURE__ */ new Set();
144615
+ let relationCount = 0;
144616
+ let truncated = false;
144617
+ for (const edge of this.listEdges(projectId)) {
144618
+ const endpoints = [
144619
+ edge.fromFileId,
144620
+ edge.toFileId,
144621
+ edge.fromSymbolId ? fileIdBySymbolId.get(edge.fromSymbolId) : void 0,
144622
+ edge.toSymbolId ? fileIdBySymbolId.get(edge.toSymbolId) : void 0
144623
+ ].filter((id) => Boolean(id));
144624
+ if (!endpoints.some((id) => changedIds.has(id))) continue;
144625
+ const relatedPaths = endpoints.filter((id) => !changedIds.has(id)).map((id) => fileById.get(id)).filter((path33) => Boolean(path33));
144626
+ if (relatedPaths.length === 0) continue;
144627
+ if (relationCount >= safeLimit2) {
144628
+ truncated = true;
144629
+ break;
144630
+ }
144631
+ relationCount += 1;
144632
+ for (const path33 of relatedPaths) direct.add(path33);
144633
+ }
144634
+ const snapshot = this.latestSnapshot(projectId);
144635
+ return {
144636
+ projectId,
144637
+ ...snapshot ? { snapshotId: snapshot.id } : {},
144638
+ changedPaths: normalizedPaths,
144639
+ directlyConnectedPaths: [...direct].sort(),
144640
+ relationCount,
144641
+ truncated,
144642
+ provider: snapshot?.provider ?? "lite"
144643
+ };
144644
+ }
144408
144645
  /**
144409
144646
  * Record a completed scan and mark all current structural facts with its
144410
144647
  * epoch. The snapshot is written only after refresh reconciliation succeeds,
@@ -144446,6 +144683,16 @@ var init_store = __esm({
144446
144683
  this.db.prepare(
144447
144684
  "UPDATE observation_code_refs SET snapshotId = ? WHERE projectId = ? AND status = 'current'"
144448
144685
  ).run(id, input.projectId);
144686
+ const snapshotFileRows = this.db.prepare(`
144687
+ SELECT id, projectId, path, contentHash FROM code_files WHERE projectId = ? ORDER BY path
144688
+ `).all(input.projectId);
144689
+ const insertSnapshotFile = this.db.prepare(`
144690
+ INSERT INTO code_state_snapshot_files (snapshotId, projectId, fileId, path, contentHash)
144691
+ VALUES (?, ?, ?, ?, ?)
144692
+ `);
144693
+ for (const file of snapshotFileRows) {
144694
+ insertSnapshotFile.run(id, file.projectId, file.id, file.path, file.contentHash);
144695
+ }
144449
144696
  snapshot = {
144450
144697
  ...input,
144451
144698
  id,
@@ -144611,8 +144858,8 @@ __export(lite_provider_exports, {
144611
144858
  import { createHash as createHash7 } from "crypto";
144612
144859
  import { readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
144613
144860
  import { join as join4, relative } from "path";
144614
- function hashText(text) {
144615
- return createHash7("sha256").update(text).digest("hex");
144861
+ function hashText(text2) {
144862
+ return createHash7("sha256").update(text2).digest("hex");
144616
144863
  }
144617
144864
  function extension2(path33) {
144618
144865
  const index = path33.lastIndexOf(".");
@@ -144656,19 +144903,19 @@ function walk(root, exclude, maxFiles) {
144656
144903
  visit(root);
144657
144904
  return out;
144658
144905
  }
144659
- function lineOf(text, index) {
144660
- return text.slice(0, index).split(/\r?\n/).length;
144906
+ function lineOf(text2, index) {
144907
+ return text2.slice(0, index).split(/\r?\n/).length;
144661
144908
  }
144662
- function extractSymbols(projectId, file, text, indexedAt) {
144909
+ function extractSymbols(projectId, file, text2, indexedAt) {
144663
144910
  const symbols = [];
144664
144911
  const profile = file.language ? languageProfiles[file.language] : void 0;
144665
144912
  const patterns = profile?.symbols ?? [];
144666
144913
  for (const { kind, re } of patterns) {
144667
144914
  re.lastIndex = 0;
144668
- for (const match2 of text.matchAll(re)) {
144915
+ for (const match2 of text2.matchAll(re)) {
144669
144916
  const name = match2[1];
144670
144917
  if (!name || name.includes("\n")) continue;
144671
- const startLine = lineOf(text, match2.index ?? 0);
144918
+ const startLine = lineOf(text2, match2.index ?? 0);
144672
144919
  const id = makeCodeSymbolId({ projectId, path: file.path, qualifiedName: name, kind });
144673
144920
  symbols.push({
144674
144921
  id,
@@ -144688,13 +144935,13 @@ function extractSymbols(projectId, file, text, indexedAt) {
144688
144935
  }
144689
144936
  return symbols;
144690
144937
  }
144691
- function extractImportEdges(projectId, file, text, indexedAt) {
144938
+ function extractImportEdges(projectId, file, text2, indexedAt) {
144692
144939
  const edges = [];
144693
144940
  const profile = file.language ? languageProfiles[file.language] : void 0;
144694
144941
  const imports = profile?.imports ?? [];
144695
144942
  for (const re of imports) {
144696
144943
  re.lastIndex = 0;
144697
- for (const match2 of text.matchAll(re)) {
144944
+ for (const match2 of text2.matchAll(re)) {
144698
144945
  const target = (match2[1] ?? "").trim();
144699
144946
  if (!target) continue;
144700
144947
  if (target.includes("\n")) {
@@ -144729,14 +144976,14 @@ function extractImportEdges(projectId, file, text, indexedAt) {
144729
144976
  function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
144730
144977
  const rel = normalizeCodePath(relative(projectRoot, abs));
144731
144978
  try {
144732
- const text = readFileSync6(abs, "utf-8");
144979
+ const text2 = readFileSync6(abs, "utf-8");
144733
144980
  const stat4 = fileStat ?? statSync3(abs);
144734
144981
  const file = {
144735
144982
  id: makeCodeFileId(projectId, rel),
144736
144983
  projectId,
144737
144984
  path: rel,
144738
144985
  language: languageForPath(rel),
144739
- contentHash: hashText(text),
144986
+ contentHash: hashText(text2),
144740
144987
  // Preserve filesystem precision. Rounding here made same-size edits in
144741
144988
  // a short Windows timestamp window indistinguishable to refresh.
144742
144989
  mtimeMs: Number(stat4.mtimeMs),
@@ -144746,8 +144993,8 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
144746
144993
  return {
144747
144994
  delta: {
144748
144995
  file,
144749
- symbols: extractSymbols(projectId, file, text, indexedAt),
144750
- edges: extractImportEdges(projectId, file, text, indexedAt)
144996
+ symbols: extractSymbols(projectId, file, text2, indexedAt),
144997
+ edges: extractImportEdges(projectId, file, text2, indexedAt)
144751
144998
  },
144752
144999
  unreadable: false
144753
145000
  };
@@ -145026,18 +145273,18 @@ __export(binder_exports, {
145026
145273
  function observationText(obs) {
145027
145274
  return [obs.title, obs.narrative, ...obs.facts ?? []].join("\n");
145028
145275
  }
145029
- function mentionsSymbol(text, symbol) {
145276
+ function mentionsSymbol(text2, symbol) {
145030
145277
  const name = symbol.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
145031
- return new RegExp(`(^|[^\\w$])${name}([^\\w$]|$)`).test(text);
145278
+ return new RegExp(`(^|[^\\w$])${name}([^\\w$]|$)`).test(text2);
145032
145279
  }
145033
- function identifierCandidates(text) {
145034
- return [...new Set(text.match(/[A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?/g) ?? [])];
145280
+ function identifierCandidates(text2) {
145281
+ return [...new Set(text2.match(/[A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?/g) ?? [])];
145035
145282
  }
145036
- function codeIdentifierCandidates(text) {
145283
+ function codeIdentifierCandidates(text2) {
145037
145284
  const explicit = /* @__PURE__ */ new Set();
145038
- for (const match2 of text.matchAll(/`([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)`/g)) explicit.add(match2[1]);
145039
- for (const match2 of text.matchAll(/\b([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)\s*\(/g)) explicit.add(match2[1]);
145040
- return identifierCandidates(text).filter((candidate) => explicit.has(candidate) || candidate.includes("::") || /[!?=]$/.test(candidate) || /^[A-Z]/.test(candidate) || /[_$]/.test(candidate) || /[a-z0-9][A-Z]/.test(candidate) || /[A-Z]{2}/.test(candidate));
145285
+ for (const match2 of text2.matchAll(/`([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)`/g)) explicit.add(match2[1]);
145286
+ for (const match2 of text2.matchAll(/\b([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)\s*\(/g)) explicit.add(match2[1]);
145287
+ return identifierCandidates(text2).filter((candidate) => explicit.has(candidate) || candidate.includes("::") || /[!?=]$/.test(candidate) || /^[A-Z]/.test(candidate) || /[_$]/.test(candidate) || /[a-z0-9][A-Z]/.test(candidate) || /[A-Z]{2}/.test(candidate));
145041
145288
  }
145042
145289
  function fileRef(projectId, obs, file) {
145043
145290
  return {
@@ -145067,7 +145314,7 @@ function symbolRef(projectId, obs, file, symbol) {
145067
145314
  }
145068
145315
  function resolveObservationCodeRefs(obs, lookup2) {
145069
145316
  const refs = /* @__PURE__ */ new Map();
145070
- const text = observationText(obs);
145317
+ const text2 = observationText(obs);
145071
145318
  const candidateFiles = /* @__PURE__ */ new Map();
145072
145319
  for (const rawPath of obs.filesModified ?? []) {
145073
145320
  const file = lookup2.findFile(normalizeCodePath(rawPath));
@@ -145077,7 +145324,7 @@ function resolveObservationCodeRefs(obs, lookup2) {
145077
145324
  refs.set(ref.id, ref);
145078
145325
  }
145079
145326
  const hintedFileIds = new Set(candidateFiles.keys());
145080
- const symbolNames = hintedFileIds.size > 0 ? identifierCandidates(text) : codeIdentifierCandidates(text);
145327
+ const symbolNames = hintedFileIds.size > 0 ? identifierCandidates(text2) : codeIdentifierCandidates(text2);
145081
145328
  const symbols = lookup2.findSymbols(symbolNames, [...hintedFileIds]);
145082
145329
  const symbolsByName = /* @__PURE__ */ new Map();
145083
145330
  for (const symbol of symbols) {
@@ -145088,7 +145335,7 @@ function resolveObservationCodeRefs(obs, lookup2) {
145088
145335
  for (const group of symbolsByName.values()) {
145089
145336
  const candidates = group.length === 1 ? group : [];
145090
145337
  for (const symbol of candidates) {
145091
- if (!mentionsSymbol(text, symbol)) continue;
145338
+ if (!mentionsSymbol(text2, symbol)) continue;
145092
145339
  const file = candidateFiles.get(symbol.fileId) ?? lookup2.findFile(symbol.path);
145093
145340
  if (!file) continue;
145094
145341
  candidateFiles.set(file.id, file);
@@ -145816,8 +146063,8 @@ function taskTokens(task) {
145816
146063
  return normalizedTokens(task);
145817
146064
  }
145818
146065
  function scoreClaim(claim, tokens) {
145819
- const text = [claim.subject, claim.predicate, claim.objectValue].join(" ").toLocaleLowerCase("en-US");
145820
- const words = normalizedTokens(text);
146066
+ const text2 = [claim.subject, claim.predicate, claim.objectValue].join(" ").toLocaleLowerCase("en-US");
146067
+ const words = normalizedTokens(text2);
145821
146068
  let matches = 0;
145822
146069
  for (const token of tokens) {
145823
146070
  if (words.has(token)) matches += 1;
@@ -146717,6 +146964,128 @@ var init_workflow_store = __esm({
146717
146964
  }
146718
146965
  });
146719
146966
 
146967
+ // src/knowledge/outcome-types.ts
146968
+ function qualityFromOutcome(signal) {
146969
+ if (!signal) return void 0;
146970
+ if (signal.kind === "verification-failed" || signal.kind === "user-correction" || signal.kind === "source-changed" || signal.kind === "conflict-confirmed") {
146971
+ return "degraded";
146972
+ }
146973
+ if (signal.kind === "verification-passed" || signal.kind === "verified-reuse" || signal.kind === "user-pin") {
146974
+ return "verified";
146975
+ }
146976
+ return void 0;
146977
+ }
146978
+ var MEMORY_OUTCOME_CANDIDATE_KINDS, MEMORY_OUTCOME_SIGNAL_KINDS;
146979
+ var init_outcome_types = __esm({
146980
+ "src/knowledge/outcome-types.ts"() {
146981
+ "use strict";
146982
+ init_esm_shims();
146983
+ MEMORY_OUTCOME_CANDIDATE_KINDS = ["claim", "durable-memory", "workflow"];
146984
+ MEMORY_OUTCOME_SIGNAL_KINDS = [
146985
+ "verification-passed",
146986
+ "verification-failed",
146987
+ "verified-reuse",
146988
+ "user-pin",
146989
+ "user-correction",
146990
+ "source-changed",
146991
+ "conflict-confirmed",
146992
+ "manual-review"
146993
+ ];
146994
+ }
146995
+ });
146996
+
146997
+ // src/knowledge/outcome-store.ts
146998
+ import { randomUUID as randomUUID10 } from "crypto";
146999
+ function optionalText4(value) {
147000
+ return typeof value === "string" && value.trim() ? value : void 0;
147001
+ }
147002
+ function text(value, field, max = 1e3) {
147003
+ const safe = sanitizeCredentials(value).replace(/\s+/g, " ").trim();
147004
+ if (!safe) throw new Error("Outcome signal " + field + " is required.");
147005
+ if (safe.length > max) throw new Error("Outcome signal " + field + " is too long.");
147006
+ return safe;
147007
+ }
147008
+ function oneOf(value, values, field) {
147009
+ if (typeof value !== "string" || !values.includes(value)) {
147010
+ throw new Error("Outcome signal " + field + " is invalid.");
147011
+ }
147012
+ return value;
147013
+ }
147014
+ function rowToSignal(row) {
147015
+ return {
147016
+ id: row.id,
147017
+ projectId: row.projectId,
147018
+ candidateKind: row.candidateKind,
147019
+ candidateId: row.candidateId,
147020
+ kind: row.kind,
147021
+ sourceRef: row.sourceRef,
147022
+ ...optionalText4(row.snapshotId) ? { snapshotId: row.snapshotId } : {},
147023
+ ...optionalText4(row.detail) ? { detail: row.detail } : {},
147024
+ observedAt: row.observedAt
147025
+ };
147026
+ }
147027
+ var OutcomeStore;
147028
+ var init_outcome_store = __esm({
147029
+ "src/knowledge/outcome-store.ts"() {
147030
+ "use strict";
147031
+ init_esm_shims();
147032
+ init_secret_filter();
147033
+ init_sqlite_db();
147034
+ init_outcome_types();
147035
+ OutcomeStore = class {
147036
+ db = null;
147037
+ async init(dataDir) {
147038
+ this.db = getDatabase(dataDir);
147039
+ }
147040
+ record(input) {
147041
+ const signal = {
147042
+ id: randomUUID10(),
147043
+ projectId: text(input.projectId, "project id"),
147044
+ candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
147045
+ candidateId: text(input.candidateId, "candidate id"),
147046
+ kind: oneOf(input.kind, MEMORY_OUTCOME_SIGNAL_KINDS, "kind"),
147047
+ sourceRef: text(input.sourceRef, "source reference"),
147048
+ ...input.snapshotId ? { snapshotId: text(input.snapshotId, "snapshot id") } : {},
147049
+ ...input.detail ? { detail: text(input.detail, "detail") } : {},
147050
+ observedAt: input.observedAt ?? (/* @__PURE__ */ new Date()).toISOString()
147051
+ };
147052
+ this.db.prepare(`
147053
+ INSERT INTO memory_outcome_signals (
147054
+ id, projectId, candidateKind, candidateId, kind, sourceRef, snapshotId, detail, observedAt
147055
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
147056
+ `).run(
147057
+ signal.id,
147058
+ signal.projectId,
147059
+ signal.candidateKind,
147060
+ signal.candidateId,
147061
+ signal.kind,
147062
+ signal.sourceRef,
147063
+ signal.snapshotId ?? null,
147064
+ signal.detail ?? null,
147065
+ signal.observedAt
147066
+ );
147067
+ return signal;
147068
+ }
147069
+ latestForCandidates(projectId, candidateKind, candidateIds) {
147070
+ const ids = [...new Set(candidateIds.filter(Boolean))];
147071
+ if (ids.length === 0) return /* @__PURE__ */ new Map();
147072
+ const placeholders = ids.map(() => "?").join(", ");
147073
+ const rows = this.db.prepare(`
147074
+ SELECT * FROM memory_outcome_signals
147075
+ WHERE projectId = ? AND candidateKind = ? AND candidateId IN (${placeholders})
147076
+ ORDER BY observedAt DESC, id DESC
147077
+ `).all(projectId, candidateKind, ...ids);
147078
+ const latest = /* @__PURE__ */ new Map();
147079
+ for (const row of rows) {
147080
+ const signal = rowToSignal(row);
147081
+ if (!latest.has(signal.candidateId)) latest.set(signal.candidateId, signal);
147082
+ }
147083
+ return latest;
147084
+ }
147085
+ };
147086
+ }
147087
+ });
147088
+
146720
147089
  // src/codegraph/task-lens.ts
146721
147090
  var task_lens_exports = {};
146722
147091
  __export(task_lens_exports, {
@@ -146733,31 +147102,31 @@ __export(task_lens_exports, {
146733
147102
  function normalizePath2(path33) {
146734
147103
  return path33.replace(/\\/g, "/");
146735
147104
  }
146736
- function tokenize3(text) {
146737
- return (text.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
147105
+ function tokenize3(text2) {
147106
+ return (text2.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
146738
147107
  }
146739
- function containsTaskKeyword(text, keyword) {
147108
+ function containsTaskKeyword(text2, keyword) {
146740
147109
  const matcher = /^[a-z0-9_-]+$/i.test(keyword) ? new RegExp(`(^|[^a-z0-9_-])${keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?=[^a-z0-9_-]|$)`, "gi") : new RegExp(keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
146741
147110
  let match2;
146742
- while ((match2 = matcher.exec(text)) !== null) {
147111
+ while ((match2 = matcher.exec(text2)) !== null) {
146743
147112
  const keywordIndex = match2.index + (match2[1]?.length ?? 0);
146744
- if (!isNegatedTaskKeyword(text, keywordIndex)) return true;
147113
+ if (!isNegatedTaskKeyword(text2, keywordIndex)) return true;
146745
147114
  }
146746
147115
  return false;
146747
147116
  }
146748
- function isNegatedTaskKeyword(text, keywordIndex) {
147117
+ function isNegatedTaskKeyword(text2, keywordIndex) {
146749
147118
  const boundary = Math.max(
146750
- text.lastIndexOf(".", keywordIndex - 1),
146751
- text.lastIndexOf("!", keywordIndex - 1),
146752
- text.lastIndexOf("?", keywordIndex - 1),
146753
- text.lastIndexOf(";", keywordIndex - 1),
146754
- text.lastIndexOf("\n", keywordIndex - 1),
146755
- text.lastIndexOf("\u3002", keywordIndex - 1),
146756
- text.lastIndexOf("\uFF01", keywordIndex - 1),
146757
- text.lastIndexOf("\uFF1F", keywordIndex - 1),
146758
- text.lastIndexOf("\uFF1B", keywordIndex - 1)
147119
+ text2.lastIndexOf(".", keywordIndex - 1),
147120
+ text2.lastIndexOf("!", keywordIndex - 1),
147121
+ text2.lastIndexOf("?", keywordIndex - 1),
147122
+ text2.lastIndexOf(";", keywordIndex - 1),
147123
+ text2.lastIndexOf("\n", keywordIndex - 1),
147124
+ text2.lastIndexOf("\u3002", keywordIndex - 1),
147125
+ text2.lastIndexOf("\uFF01", keywordIndex - 1),
147126
+ text2.lastIndexOf("\uFF1F", keywordIndex - 1),
147127
+ text2.lastIndexOf("\uFF1B", keywordIndex - 1)
146759
147128
  );
146760
- let prefix = text.slice(boundary + 1, keywordIndex).toLowerCase();
147129
+ let prefix = text2.slice(boundary + 1, keywordIndex).toLowerCase();
146761
147130
  const contrast = /(?:,|\uff0c)\s*(?:but|however|instead|yet|\u4f46\u662f|\u4f46|\u800c\u662f)\s*/gi;
146762
147131
  let contrastMatch;
146763
147132
  let contrastEnd = -1;
@@ -146780,9 +147149,9 @@ function resolveTaskLens(task) {
146780
147149
  };
146781
147150
  for (const id of LENS_PRIORITY) {
146782
147151
  const score = KEYWORDS[id].reduce((sum, keyword) => sum + (containsTaskKeyword(normalized, keyword) ? 1 : 0), 0);
146783
- const priority = LENS_PRIORITY.indexOf(id);
146784
- if (score > best.score || score === best.score && score > 0 && priority < best.priority) {
146785
- best = { id, score, priority };
147152
+ const priority2 = LENS_PRIORITY.indexOf(id);
147153
+ if (score > best.score || score === best.score && score > 0 && priority2 < best.priority) {
147154
+ best = { id, score, priority: priority2 };
146786
147155
  }
146787
147156
  }
146788
147157
  return best.score > 0 ? LENSES[best.id] : LENSES.general;
@@ -146824,20 +147193,20 @@ function pathKindScore(path33, lens) {
146824
147193
  return 0;
146825
147194
  }
146826
147195
  }
146827
- function tokenScore(text, tokens) {
147196
+ function tokenScore(text2, tokens) {
146828
147197
  if (tokens.length === 0) return 0;
146829
- const normalized = text.toLowerCase();
147198
+ const normalized = text2.toLowerCase();
146830
147199
  return tokens.reduce((sum, token) => sum + (normalized.includes(token) ? 12 : 0), 0);
146831
147200
  }
146832
147201
  function sourceTaskMatchScore(source, task) {
146833
147202
  const tokens = tokenize3(task ?? "");
146834
147203
  if (tokens.length === 0) return 0;
146835
- const text = [
147204
+ const text2 = [
146836
147205
  source.title,
146837
147206
  source.path ?? "",
146838
147207
  source.symbol ?? ""
146839
147208
  ].join("\n").toLowerCase();
146840
- const matches = tokens.filter((token) => text.includes(token)).length;
147209
+ const matches = tokens.filter((token) => text2.includes(token)).length;
146841
147210
  if (matches >= 2) return 40;
146842
147211
  if (matches === 1) return 24;
146843
147212
  return 0;
@@ -146876,8 +147245,8 @@ function lensPathCandidates(lens) {
146876
147245
  }
146877
147246
  function scoreLensSource(source, lens, task) {
146878
147247
  const tokens = tokenize3(task ?? "");
146879
- const text = [source.title, source.type, source.path ?? "", source.symbol ?? ""].join("\n");
146880
- return pathKindScore(source.path ?? "", lens) + tokenScore(text, tokens) + sourceTaskMatchScore(source, task);
147248
+ const text2 = [source.title, source.type, source.path ?? "", source.symbol ?? ""].join("\n");
147249
+ return pathKindScore(source.path ?? "", lens) + tokenScore(text2, tokens) + sourceTaskMatchScore(source, task);
146881
147250
  }
146882
147251
  function rankLensSources(sources, lens, task) {
146883
147252
  return [...sources].map((source, index) => ({
@@ -147120,7 +147489,7 @@ function requiredText(data, key) {
147120
147489
  }
147121
147490
  return value.trim();
147122
147491
  }
147123
- function optionalText4(data, key) {
147492
+ function optionalText5(data, key) {
147124
147493
  const value = data[key];
147125
147494
  if (value === void 0 || value === null || value === "") return void 0;
147126
147495
  if (typeof value !== "string") throw new Error("workflow frontmatter field " + key + " must be text");
@@ -147163,11 +147532,11 @@ function phaseFromValue(value, index) {
147163
147532
  }
147164
147533
  const data = value;
147165
147534
  const title = requiredText(data, "title");
147166
- const phaseId = optionalText4(data, "id") ?? slug(title) + "-" + (index + 1);
147535
+ const phaseId = optionalText5(data, "id") ?? slug(title) + "-" + (index + 1);
147167
147536
  return {
147168
147537
  id: phaseId,
147169
147538
  title,
147170
- instructions: optionalText4(data, "instructions") ?? "",
147539
+ instructions: optionalText5(data, "instructions") ?? "",
147171
147540
  branches: optionalStringArray(data, "branches"),
147172
147541
  expectedOutputs: optionalStringArray(data, "expectedOutputs"),
147173
147542
  verificationGates: optionalStringArray(data, "verificationGates")
@@ -147276,7 +147645,7 @@ function parsedWorkflow(data, body, input) {
147276
147645
  id: requiredText(data, "id"),
147277
147646
  workspaceId: input.workspaceId,
147278
147647
  title: requiredText(data, "title"),
147279
- description: optionalText4(data, "description") ?? "",
147648
+ description: optionalText5(data, "description") ?? "",
147280
147649
  status: optionalStatus(data),
147281
147650
  version: optionalNumber(data, "version", 1),
147282
147651
  taskLenses: optionalStringArray(data, "taskLenses"),
@@ -147295,9 +147664,9 @@ function parsedWorkflow(data, body, input) {
147295
147664
  sourcePath: normalizeSourcePath(input.sourcePath),
147296
147665
  sourceHash: "",
147297
147666
  contentHash: input.contentHash,
147298
- createdAt: optionalText4(data, "createdAt") ?? now2(),
147299
- updatedAt: optionalText4(data, "updatedAt") ?? now2(),
147300
- ...optionalText4(data, "importedFrom") ? { importedFrom: optionalText4(data, "importedFrom") } : {}
147667
+ createdAt: optionalText5(data, "createdAt") ?? now2(),
147668
+ updatedAt: optionalText5(data, "updatedAt") ?? now2(),
147669
+ ...optionalText5(data, "importedFrom") ? { importedFrom: optionalText5(data, "importedFrom") } : {}
147301
147670
  };
147302
147671
  if (candidate.phases.length === 0) {
147303
147672
  throw new Error("workflow must contain at least one phase or a non-empty body");
@@ -147396,11 +147765,11 @@ async function syncCanonicalWorkflows(workspace) {
147396
147765
  return { workflows, errors };
147397
147766
  }
147398
147767
  function inferTaskLenses(value) {
147399
- const text = value.toLowerCase();
147400
- return Object.entries(LENS_TERMS).filter(([, terms]) => terms.some((term) => text.includes(term))).map(([lens]) => lens);
147768
+ const text2 = value.toLowerCase();
147769
+ return Object.entries(LENS_TERMS).filter(([, terms]) => terms.some((term) => text2.includes(term))).map(([lens]) => lens);
147401
147770
  }
147402
147771
  function taskScore(workflow, task) {
147403
- const text = task.toLowerCase();
147772
+ const text2 = task.toLowerCase();
147404
147773
  let score = 0;
147405
147774
  const reasons = [];
147406
147775
  const matchedLenses = /* @__PURE__ */ new Set();
@@ -147667,7 +148036,31 @@ async function recordWorkflowRun(input) {
147667
148036
  throw new Error("Workflow was not found for this workspace");
147668
148037
  }
147669
148038
  if (!input.run.task.trim()) throw new Error("Workflow run task is required");
147670
- return store.recordRun(input.run);
148039
+ const run = store.recordRun(input.run);
148040
+ const kind = run.outcome === "passed" && run.verificationVerdict === "passed" ? "verification-passed" : run.outcome === "failed" || run.verificationVerdict === "failed" ? "verification-failed" : void 0;
148041
+ if (!kind) return run;
148042
+ const evidence = /* @__PURE__ */ new Map();
148043
+ evidence.set(workflow.id, "workflow");
148044
+ for (const reference of run.selectedEvidence) {
148045
+ const match2 = /^(claim|durable):(.+)$/.exec(reference);
148046
+ if (!match2) continue;
148047
+ evidence.set(match2[2], match2[1] === "claim" ? "claim" : "durable-memory");
148048
+ }
148049
+ const outcomes = new OutcomeStore();
148050
+ await outcomes.init(workflowStoreDataDir(input.workspace));
148051
+ for (const [candidateId, candidateKind] of evidence) {
148052
+ outcomes.record({
148053
+ projectId: run.projectId,
148054
+ candidateKind,
148055
+ candidateId,
148056
+ kind,
148057
+ sourceRef: "workflow-run:" + run.id,
148058
+ ...run.startingSnapshotId ? { snapshotId: run.startingSnapshotId } : {},
148059
+ ...run.failureReason ? { detail: run.failureReason } : {},
148060
+ observedAt: run.completedAt ?? run.startedAt
148061
+ });
148062
+ }
148063
+ return run;
147671
148064
  }
147672
148065
  async function selectWorkspaceWorkflows(input) {
147673
148066
  const synced = await syncCanonicalWorkflows(input.workspace);
@@ -147692,6 +148085,7 @@ var init_workflows2 = __esm({
147692
148085
  init_workflow_sync();
147693
148086
  init_workspace();
147694
148087
  init_workflow_store();
148088
+ init_outcome_store();
147695
148089
  init_task_lens();
147696
148090
  KNOWN_AGENTS = [
147697
148091
  "windsurf",
@@ -149717,8 +150111,8 @@ async function extractFactsWithLLM(narrative, title, existingFacts) {
149717
150111
  Content: ${narrative}${existingFacts.length > 0 ? `
149718
150112
  Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
149719
150113
  const response = await callLLM2(LLM_EXTRACT_PROMPT, input);
149720
- const text = response.content.trim();
149721
- const jsonMatch = text.match(/\{[\s\S]*\}/);
150114
+ const text2 = response.content.trim();
150115
+ const jsonMatch = text2.match(/\{[\s\S]*\}/);
149722
150116
  if (!jsonMatch) return [];
149723
150117
  const parsed = JSON.parse(jsonMatch[0]);
149724
150118
  const facts = parsed.facts;
@@ -149971,8 +150365,8 @@ Facts: ${extracted.facts.join("; ")}
149971
150365
  EXISTING MEMORIES:
149972
150366
  ${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Facts: ${m2.facts}`).join("\n")}`;
149973
150367
  const response = await callLLM2(LLM_RESOLVE_PROMPT, input);
149974
- const text = response.content.trim();
149975
- const jsonMatch = text.match(/\{[\s\S]*\}/);
150368
+ const text2 = response.content.trim();
150369
+ const jsonMatch = text2.match(/\{[\s\S]*\}/);
149976
150370
  if (!jsonMatch) return null;
149977
150371
  const parsed = JSON.parse(jsonMatch[0]);
149978
150372
  const action = parsed.action?.toUpperCase();
@@ -150753,8 +151147,8 @@ function isNoiseObservation(obs) {
150753
151147
  return NOISE_PATTERNS2.some((pattern) => pattern.test(title)) || isCommandTrace(obs);
150754
151148
  }
150755
151149
  function isSystemSelfObservation(obs) {
150756
- const text = stringifyObservation(obs, false);
150757
- return SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(text));
151150
+ const text2 = stringifyObservation(obs, false);
151151
+ return SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(text2));
150758
151152
  }
150759
151153
  function readerForAlias(reader, aliases, observation) {
150760
151154
  if (!reader) return void 0;
@@ -150777,8 +151171,8 @@ function continuationTaskTokens(task) {
150777
151171
  function continuationScore(observation, projectTokens, task) {
150778
151172
  let score = scoreObservationForSessionContext(observation, projectTokens);
150779
151173
  if (observation.type === "session-request" || observation.type === "what-changed") score += 1;
150780
- const text = stringifyObservation(observation);
150781
- const matches = continuationTaskTokens(task).filter((token) => text.includes(token)).length;
151174
+ const text2 = stringifyObservation(observation);
151175
+ const matches = continuationTaskTokens(task).filter((token) => text2.includes(token)).length;
150782
151176
  score += Math.min(matches, 2) * 2;
150783
151177
  return score;
150784
151178
  }
@@ -150812,8 +151206,8 @@ async function getSessionResumeBrief(projectId, task, reader) {
150812
151206
  memories
150813
151207
  };
150814
151208
  }
150815
- function compactResumeText(text, limit2) {
150816
- const normalized = text.replace(/\s+/g, " ").trim();
151209
+ function compactResumeText(text2, limit2) {
151210
+ const normalized = text2.replace(/\s+/g, " ").trim();
150817
151211
  return normalized.length <= limit2 ? normalized : `${normalized.slice(0, Math.max(0, limit2 - 3)).trimEnd()}...`;
150818
151212
  }
150819
151213
  function renderSessionResumeCard(brief) {
@@ -150835,11 +151229,11 @@ function renderSessionResumeCard(brief) {
150835
151229
  }
150836
151230
  function scoreObservationForSessionContext(obs, projectTokens, now3 = Date.now()) {
150837
151231
  let score = TYPE_WEIGHTS2[obs.type] ?? 1;
150838
- const text = stringifyObservation(obs);
151232
+ const text2 = stringifyObservation(obs);
150839
151233
  const ageDays = Math.max(0, (now3 - new Date(obs.createdAt).getTime()) / (1e3 * 60 * 60 * 24));
150840
151234
  score += Math.max(0.2, 2.5 - Math.min(ageDays, 45) * 0.05);
150841
151235
  if (projectTokens.length > 0) {
150842
- const matchingTokens = projectTokens.filter((token) => text.includes(token));
151236
+ const matchingTokens = projectTokens.filter((token) => text2.includes(token));
150843
151237
  if (matchingTokens.length > 0) {
150844
151238
  score += 2 + matchingTokens.length * 0.6;
150845
151239
  } else if ((obs.filesModified?.length ?? 0) > 0) {
@@ -151155,7 +151549,7 @@ var owner_exports = {};
151155
151549
  __export(owner_exports, {
151156
151550
  resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
151157
151551
  });
151158
- import { randomUUID as randomUUID10 } from "crypto";
151552
+ import { randomUUID as randomUUID11 } from "crypto";
151159
151553
  import { promises as fs17 } from "fs";
151160
151554
  import path25 from "path";
151161
151555
  function ownerPath(dataDir) {
@@ -151185,7 +151579,7 @@ async function resolveLocalMemoryOwner(dataDir, options = {}) {
151185
151579
  await fs17.mkdir(path25.dirname(filePath), { recursive: true });
151186
151580
  const created = {
151187
151581
  version: 1,
151188
- id: "local-" + randomUUID10(),
151582
+ id: "local-" + randomUUID11(),
151189
151583
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
151190
151584
  };
151191
151585
  try {
@@ -151208,8 +151602,8 @@ var init_owner = __esm({
151208
151602
  });
151209
151603
 
151210
151604
  // src/memory/long-term-store.ts
151211
- import { randomUUID as randomUUID11 } from "crypto";
151212
- function optionalText5(value) {
151605
+ import { randomUUID as randomUUID12 } from "crypto";
151606
+ function optionalText6(value) {
151213
151607
  return typeof value === "string" && value.trim() ? value : void 0;
151214
151608
  }
151215
151609
  function arrayValue2(value) {
@@ -151234,17 +151628,17 @@ function rowToMemory(row) {
151234
151628
  content: row.content,
151235
151629
  facts: arrayValue2(row.factsJson),
151236
151630
  tags: arrayValue2(row.tagsJson),
151237
- ...optionalText5(row.applicability) ? { applicability: row.applicability } : {},
151631
+ ...optionalText6(row.applicability) ? { applicability: row.applicability } : {},
151238
151632
  origin: row.origin,
151239
151633
  createdAt: row.createdAt,
151240
151634
  updatedAt: row.updatedAt,
151241
- ...optionalText5(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
151242
- ...optionalText5(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
151243
- ...optionalText5(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
151244
- ...optionalText5(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
151245
- ...optionalText5(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
151635
+ ...optionalText6(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
151636
+ ...optionalText6(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
151637
+ ...optionalText6(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
151638
+ ...optionalText6(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
151639
+ ...optionalText6(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
151246
151640
  accessCount: Number(row.accessCount ?? 0),
151247
- ...optionalText5(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
151641
+ ...optionalText6(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
151248
151642
  };
151249
151643
  }
151250
151644
  function rowToEvidence2(row) {
@@ -151254,8 +151648,8 @@ function rowToEvidence2(row) {
151254
151648
  kind: row.kind,
151255
151649
  referenceId: row.referenceId,
151256
151650
  relation: row.relation,
151257
- ...optionalText5(row.locator) ? { locator: row.locator } : {},
151258
- ...optionalText5(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
151651
+ ...optionalText6(row.locator) ? { locator: row.locator } : {},
151652
+ ...optionalText6(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
151259
151653
  createdAt: row.createdAt
151260
151654
  };
151261
151655
  }
@@ -151264,9 +151658,9 @@ function rowToEvent2(row) {
151264
151658
  id: row.id,
151265
151659
  memoryId: row.memoryId,
151266
151660
  kind: row.kind,
151267
- ...optionalText5(row.fromState) ? { fromState: row.fromState } : {},
151268
- ...optionalText5(row.toState) ? { toState: row.toState } : {},
151269
- ...optionalText5(row.detail) ? { detail: row.detail } : {},
151661
+ ...optionalText6(row.fromState) ? { fromState: row.fromState } : {},
151662
+ ...optionalText6(row.toState) ? { toState: row.toState } : {},
151663
+ ...optionalText6(row.detail) ? { detail: row.detail } : {},
151270
151664
  createdAt: row.createdAt
151271
151665
  };
151272
151666
  }
@@ -151368,7 +151762,7 @@ var init_long_term_store = __esm({
151368
151762
  }
151369
151763
  insertEvidence(input) {
151370
151764
  const evidence = {
151371
- id: randomUUID11(),
151765
+ id: randomUUID12(),
151372
151766
  ...input,
151373
151767
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
151374
151768
  };
@@ -151395,7 +151789,7 @@ var init_long_term_store = __esm({
151395
151789
  }
151396
151790
  recordEvent(input) {
151397
151791
  const event = {
151398
- id: randomUUID11(),
151792
+ id: randomUUID12(),
151399
151793
  ...input,
151400
151794
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
151401
151795
  };
@@ -151483,7 +151877,7 @@ __export(long_term_exports, {
151483
151877
  selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
151484
151878
  supersedeLongTermMemory: () => supersedeLongTermMemory
151485
151879
  });
151486
- import { randomUUID as randomUUID12 } from "crypto";
151880
+ import { randomUUID as randomUUID13 } from "crypto";
151487
151881
  function isOneOf(value, values) {
151488
151882
  return typeof value === "string" && values.includes(value);
151489
151883
  }
@@ -151665,7 +152059,7 @@ async function createManualLongTermMemory(input) {
151665
152059
  const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
151666
152060
  if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
151667
152061
  assertScope(input.scope);
151668
- const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID12(), relation: "supports" }];
152062
+ const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID13(), relation: "supports" }];
151669
152063
  return createLongTermMemoryWithDataDir({
151670
152064
  dataDir: input.dataDir,
151671
152065
  originProjectId: input.projectId,
@@ -151720,7 +152114,7 @@ async function createLongTermMemoryWithDataDir(input) {
151720
152114
  assertPortableEvidence(input.scope, portability, evidenceInputs);
151721
152115
  const now3 = (/* @__PURE__ */ new Date()).toISOString();
151722
152116
  const memory = {
151723
- id: randomUUID12(),
152117
+ id: randomUUID13(),
151724
152118
  originProjectId: compactText2(input.originProjectId, "origin project id", 1e3),
151725
152119
  ownerId: compactText2(input.ownerId, "owner id", 160),
151726
152120
  scope: input.scope,
@@ -151971,12 +152365,99 @@ var init_long_term = __esm({
151971
152365
  }
151972
152366
  });
151973
152367
 
152368
+ // src/knowledge/governor.ts
152369
+ function clampRelevance(value) {
152370
+ if (!Number.isFinite(value)) return 0;
152371
+ return Math.max(0, Math.min(1, value));
152372
+ }
152373
+ function classify(candidate) {
152374
+ const freshness = candidate.freshness ?? "unknown";
152375
+ const trust = candidate.trust ?? "historical";
152376
+ const quality = candidate.quality ?? "probationary";
152377
+ const conflict = candidate.conflict ?? "none";
152378
+ if (!candidate.scopeAllowed) {
152379
+ return { disposition: "exclude", reasons: ["scope-forbidden"] };
152380
+ }
152381
+ if (conflict === "confirmed") {
152382
+ return { disposition: "exclude", reasons: ["confirmed-conflict"] };
152383
+ }
152384
+ if (quality === "blocked") {
152385
+ return { disposition: "exclude", reasons: ["blocked-quality"] };
152386
+ }
152387
+ if (quality === "degraded") {
152388
+ return { disposition: "defer", reasons: ["degraded-quality"] };
152389
+ }
152390
+ if (freshness === "stale") {
152391
+ return { disposition: "defer", reasons: ["stale-evidence"] };
152392
+ }
152393
+ const reasons = [];
152394
+ let disposition = "include";
152395
+ if (freshness === "unknown") {
152396
+ disposition = "compact";
152397
+ reasons.push("unknown-freshness");
152398
+ }
152399
+ if (conflict === "possible") {
152400
+ disposition = "compact";
152401
+ reasons.push("possible-conflict");
152402
+ }
152403
+ if (quality === "probationary") {
152404
+ disposition = "compact";
152405
+ reasons.push("probationary-evidence");
152406
+ }
152407
+ if (disposition === "include" && freshness === "current" && trust === "source-backed") {
152408
+ reasons.push("current-source-backed-evidence");
152409
+ } else if (reasons.length === 0) {
152410
+ reasons.push("relevant-evidence");
152411
+ }
152412
+ return { disposition, reasons };
152413
+ }
152414
+ function priority(decision) {
152415
+ const dispositionWeight = {
152416
+ include: 3,
152417
+ compact: 2,
152418
+ defer: 1,
152419
+ exclude: 0
152420
+ };
152421
+ const evidence = Math.min(3, decision.candidate.evidenceCount ?? 0) / 10;
152422
+ return dispositionWeight[decision.disposition] + clampRelevance(decision.candidate.relevance) + evidence;
152423
+ }
152424
+ function governContextCandidates(candidates, maxTokens) {
152425
+ const safeBudget = Math.max(0, Math.floor(maxTokens));
152426
+ const decisions = candidates.map((candidate) => ({ candidate, ...classify(candidate) }));
152427
+ const eligible = decisions.filter((decision) => decision.disposition === "include" || decision.disposition === "compact").sort((left, right) => priority(right) - priority(left));
152428
+ let usedTokens = 0;
152429
+ for (const decision of eligible) {
152430
+ const tokens = Math.max(0, Math.ceil(decision.candidate.estimatedTokens));
152431
+ if (usedTokens + tokens <= safeBudget) {
152432
+ usedTokens += tokens;
152433
+ continue;
152434
+ }
152435
+ decision.disposition = "defer";
152436
+ decision.reasons = [...decision.reasons, "token-budget"];
152437
+ }
152438
+ const delivered = decisions.filter((decision) => decision.disposition === "include" || decision.disposition === "compact");
152439
+ const mode = delivered.length === 0 ? "abstain" : delivered.some((decision) => decision.disposition === "include") ? "workset" : "card";
152440
+ const cautions = [...new Set(decisions.filter((decision) => decision.disposition !== "include").flatMap((decision) => decision.reasons))];
152441
+ return {
152442
+ mode,
152443
+ budget: { maxTokens: safeBudget, usedTokens },
152444
+ decisions,
152445
+ cautions: cautions.length > 0 ? cautions : ["no-qualified-evidence"]
152446
+ };
152447
+ }
152448
+ var init_governor = __esm({
152449
+ "src/knowledge/governor.ts"() {
152450
+ "use strict";
152451
+ init_esm_shims();
152452
+ }
152453
+ });
152454
+
151974
152455
  // src/knowledge/workset.ts
151975
152456
  function unique(values) {
151976
152457
  return [...new Set(values.filter(Boolean))];
151977
152458
  }
151978
- function short(text, budget = 28) {
151979
- const safe = sanitizeCredentials(text).replace(/\s+/g, " ").trim();
152459
+ function short(text2, budget = 28) {
152460
+ const safe = sanitizeCredentials(text2).replace(/\s+/g, " ").trim();
151980
152461
  return countTextTokens(safe) <= budget ? safe : truncateToTokenBudget(safe, budget);
151981
152462
  }
151982
152463
  function claimAssertion(claim) {
@@ -152107,6 +152588,65 @@ function receiptOmissions(omitted, hiddenCautionMemoryCount) {
152107
152588
  function scheduledActions(cautions) {
152108
152589
  return cautions.filter((caution) => caution.kind === "codegraph-refresh-queued").map((caution) => short(caution.message, 28));
152109
152590
  }
152591
+ function isGovernedDelivery(disposition) {
152592
+ return disposition === "include" || disposition === "compact";
152593
+ }
152594
+ function governOptionalArtifacts(input) {
152595
+ const candidates = [
152596
+ ...input.reliableMemory.map((memory, index) => ({
152597
+ kind: "memory",
152598
+ id: "memory:" + memory.id,
152599
+ estimatedTokens: 10,
152600
+ relevance: Math.max(0.2, 0.9 - index * 0.1),
152601
+ scopeAllowed: true,
152602
+ freshness: freshnessForMemory(memory.status),
152603
+ trust: "historical",
152604
+ quality: memory.status === "current" ? "verified" : "degraded"
152605
+ })),
152606
+ ...input.claims.map((claim, index) => ({
152607
+ kind: "claim",
152608
+ id: "claim:" + claim.id,
152609
+ estimatedTokens: 12,
152610
+ relevance: Math.max(0.2, 0.95 - index * 0.1),
152611
+ scopeAllowed: true,
152612
+ freshness: claim.status === "active" ? "current" : "unknown",
152613
+ trust: "source-backed",
152614
+ quality: claim.reviewState === "approved" ? "verified" : "probationary",
152615
+ conflict: claim.status === "disputed" ? "confirmed" : "none",
152616
+ evidenceCount: claim.evidenceRefs.length
152617
+ })),
152618
+ ...input.durableMemory.map((memory, index) => ({
152619
+ kind: "durable-memory",
152620
+ id: "durable:" + memory.id,
152621
+ estimatedTokens: 14,
152622
+ relevance: Math.max(0.2, 0.8 - index * 0.1),
152623
+ scopeAllowed: true,
152624
+ freshness: memory.state === "approved" ? "current" : "unknown",
152625
+ trust: "source-backed",
152626
+ quality: memory.quality,
152627
+ evidenceCount: memory.evidenceRefs.length
152628
+ })),
152629
+ ...input.workflows.map((workflow, index) => ({
152630
+ kind: "workflow",
152631
+ id: "workflow:" + workflow.id,
152632
+ estimatedTokens: 14,
152633
+ relevance: Math.max(0.2, 0.85 - index * 0.1),
152634
+ scopeAllowed: true,
152635
+ freshness: "current",
152636
+ trust: "source-backed",
152637
+ quality: "verified"
152638
+ }))
152639
+ ];
152640
+ const plan = governContextCandidates(candidates, Number.MAX_SAFE_INTEGER);
152641
+ const permitted = new Set(plan.decisions.filter((decision) => isGovernedDelivery(decision.disposition)).map((decision) => decision.candidate.id));
152642
+ return {
152643
+ plan,
152644
+ reliableMemory: input.reliableMemory.filter((memory) => permitted.has("memory:" + memory.id)),
152645
+ claims: input.claims.filter((claim) => permitted.has("claim:" + claim.id)),
152646
+ durableMemory: input.durableMemory.filter((memory) => permitted.has("durable:" + memory.id)),
152647
+ workflows: input.workflows.filter((workflow) => permitted.has("workflow:" + workflow.id))
152648
+ };
152649
+ }
152110
152650
  function renderTaskWorksetPrompt(input) {
152111
152651
  const maxTokens = input.budget?.maxTokens ?? 180;
152112
152652
  const omitted = [];
@@ -152234,6 +152774,56 @@ function renderTaskWorksetPrompt(input) {
152234
152774
  trust: "source-backed"
152235
152775
  });
152236
152776
  }
152777
+ if (input.codeEvolution && input.codeEvolution.changes.length > 0) {
152778
+ appendLine(lines, "", maxTokens, omitted, "code-evolution-heading");
152779
+ appendLine(lines, "Code changes since prior scan", maxTokens, omitted, "code-evolution-heading");
152780
+ for (const change of input.codeEvolution.changes.slice(0, 3)) {
152781
+ appendLine(
152782
+ lines,
152783
+ "- " + change.kind + ": " + change.path,
152784
+ maxTokens,
152785
+ omitted,
152786
+ "code-evolution-change",
152787
+ selected,
152788
+ {
152789
+ kind: "code-state",
152790
+ id: "snapshot:" + input.codeEvolution.toSnapshotId,
152791
+ reason: "exact file hash change between complete CodeGraph snapshots",
152792
+ freshness: "current",
152793
+ trust: "source-backed"
152794
+ }
152795
+ );
152796
+ }
152797
+ for (const path33 of input.codeEvolution.directlyConnectedPaths.slice(0, 2)) {
152798
+ appendLine(
152799
+ lines,
152800
+ "- connected now: " + path33,
152801
+ maxTokens,
152802
+ omitted,
152803
+ "code-evolution-impact",
152804
+ selected,
152805
+ {
152806
+ kind: "code-state",
152807
+ id: "snapshot:" + input.codeEvolution.toSnapshotId,
152808
+ reason: "bounded current CodeGraph impact relation",
152809
+ freshness: "current",
152810
+ trust: "derived"
152811
+ }
152812
+ );
152813
+ }
152814
+ if ((input.codeEvolution.affectedMemoryCount ?? 0) > 0) {
152815
+ appendLine(
152816
+ lines,
152817
+ "- " + input.codeEvolution.affectedMemoryCount + " stored memory link(s) reference this changed code; reread source before relying on their conclusions.",
152818
+ maxTokens,
152819
+ omitted,
152820
+ "code-evolution-stale-memory"
152821
+ );
152822
+ }
152823
+ if (input.codeEvolution.truncated) {
152824
+ appendLine(lines, "- More connected files exist; inspect CodeGraph before assuming complete impact.", maxTokens, omitted, "code-evolution-truncated");
152825
+ }
152826
+ }
152237
152827
  if (input.semanticCode && (input.semanticCode.entryPoints.length > 0 || input.semanticCode.relations.length > 0)) {
152238
152828
  appendLine(lines, "", maxTokens, omitted, "semantic-code-heading");
152239
152829
  appendLine(lines, "Semantic code outline", maxTokens, omitted, "semantic-code-heading");
@@ -152424,6 +153014,17 @@ async function buildTaskWorkset(input) {
152424
153014
  }));
152425
153015
  let durableMemory = [];
152426
153016
  let durableEvidence = [];
153017
+ let outcomeStore;
153018
+ try {
153019
+ outcomeStore = new OutcomeStore();
153020
+ await outcomeStore.init(input.dataDir);
153021
+ } catch {
153022
+ }
153023
+ const claimQuality = outcomeStore ? outcomeStore.latestForCandidates(input.projectId, "claim", claims.map((claim) => claim.id)) : /* @__PURE__ */ new Map();
153024
+ for (const claim of claims) {
153025
+ const outcomeQuality = qualityFromOutcome(claimQuality.get(claim.id));
153026
+ if (outcomeQuality === "degraded") claim.reviewState = "needs-review";
153027
+ }
152427
153028
  if (task) {
152428
153029
  try {
152429
153030
  const selected = await selectLongTermMemoriesForTask({
@@ -152434,11 +153035,13 @@ async function buildTaskWorkset(input) {
152434
153035
  ...input.reader?.isTeamMember ? { isTeamMember: true } : {},
152435
153036
  limit: 3
152436
153037
  });
153038
+ const durableQuality = outcomeStore ? outcomeStore.latestForCandidates(input.projectId, "durable-memory", selected.map((item) => item.memory.id)) : /* @__PURE__ */ new Map();
152437
153039
  durableMemory = selected.map((item) => ({
152438
153040
  id: item.memory.id,
152439
153041
  kind: item.memory.kind,
152440
153042
  scope: item.memory.scope,
152441
153043
  state: item.memory.state,
153044
+ quality: qualityFromOutcome(durableQuality.get(item.memory.id)) ?? (item.memory.state === "approved" ? "verified" : "probationary"),
152442
153045
  title: item.memory.title,
152443
153046
  summary: renderLongTermMemorySummary(item.memory, 20),
152444
153047
  evidenceRefs: item.evidence.map((evidence) => evidence.id),
@@ -152484,18 +153087,25 @@ async function buildTaskWorkset(input) {
152484
153087
  }
152485
153088
  } catch {
152486
153089
  }
152487
- const evidenceIds = unique(selection.claims.flatMap((claim) => evidenceIdsForClaim(
152488
- claim,
152489
- evidenceByClaim.get(claim.id) ?? []
152490
- )).concat(
152491
- durableMemory.map((memory) => "durable:" + memory.id),
152492
- durableEvidence.map((evidence) => "durable-evidence:" + evidence.id)
152493
- ));
152494
153090
  const verification = unique([
152495
153091
  ...workflows.flatMap((workflow) => workflow.verificationGates),
152496
153092
  ...input.verificationHints
152497
153093
  ]).slice(0, 4);
152498
153094
  const normalizedCautions = unique(cautions.map((caution) => caution.kind)).map((kind) => cautions.find((caution) => caution.kind === kind)).slice(0, 6);
153095
+ const governed = governOptionalArtifacts({
153096
+ reliableMemory: input.reliableMemory?.slice(0, 3) ?? [],
153097
+ claims,
153098
+ durableMemory,
153099
+ workflows
153100
+ });
153101
+ const governedDurableIds = new Set(governed.durableMemory.map((memory) => memory.id));
153102
+ const evidenceIds = unique(governed.claims.flatMap((claim) => evidenceIdsForClaim(
153103
+ claim,
153104
+ evidenceByClaim.get(claim.id) ?? []
153105
+ )).concat(
153106
+ governed.durableMemory.map((memory) => "durable:" + memory.id),
153107
+ durableEvidence.filter((evidence) => governedDurableIds.has(evidence.memoryId)).map((evidence) => "durable-evidence:" + evidence.id)
153108
+ ));
152499
153109
  const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0 || input.continuation.compactCheckpoint) ? {
152500
153110
  ...input.continuation.previousSession ? {
152501
153111
  previousSession: {
@@ -152522,15 +153132,16 @@ async function buildTaskWorkset(input) {
152522
153132
  currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
152523
153133
  ...continuation ? { continuation } : {},
152524
153134
  ...input.codeState ? { codeState: short(input.codeState, 28) } : {},
153135
+ ...input.codeEvolution ? { codeEvolution: input.codeEvolution } : {},
152525
153136
  startHere: unique(input.startHere).slice(0, 5),
152526
153137
  ...input.semanticCode ? { semanticCode: input.semanticCode } : {},
152527
- reliableMemory: input.reliableMemory?.slice(0, 3) ?? [],
153138
+ reliableMemory: governed.reliableMemory,
152528
153139
  cautionMemory: input.cautionMemory?.slice(0, 3) ?? [],
152529
153140
  hiddenCautionMemoryCount: input.hiddenCautionMemoryCount ?? 0,
152530
- claims,
152531
- pages,
152532
- durableMemory,
152533
- workflows,
153141
+ claims: governed.claims,
153142
+ pages: pages.filter((page) => page.claimIds.some((claimId) => governed.claims.some((claim) => claim.id === claimId))),
153143
+ durableMemory: governed.durableMemory,
153144
+ workflows: governed.workflows,
152534
153145
  cautions: normalizedCautions,
152535
153146
  verification,
152536
153147
  evidenceIds,
@@ -152555,6 +153166,17 @@ async function buildTaskWorkset(input) {
152555
153166
  },
152556
153167
  selected: rendered.selected,
152557
153168
  omitted: receiptOmissions(rendered.omittedItems, base.hiddenCautionMemoryCount),
153169
+ governance: {
153170
+ scope: "optional-evidence",
153171
+ mode: governed.plan.mode,
153172
+ decisions: governed.plan.decisions.map((decision) => ({
153173
+ kind: decision.candidate.kind,
153174
+ ...decision.candidate.id ? { id: decision.candidate.id } : {},
153175
+ disposition: decision.disposition,
153176
+ reasons: decision.reasons
153177
+ })),
153178
+ cautions: governed.plan.cautions
153179
+ },
152558
153180
  scheduledActions: scheduledActions(normalizedCautions)
152559
153181
  };
152560
153182
  return {
@@ -152580,8 +153202,11 @@ var init_workset = __esm({
152580
153202
  init_workspace_store();
152581
153203
  init_workspace();
152582
153204
  init_workflow_store();
153205
+ init_outcome_store();
153206
+ init_outcome_types();
152583
153207
  init_workflows2();
152584
153208
  init_long_term();
153209
+ init_governor();
152585
153210
  CONTINUATION_DETAIL_TOKEN_BUDGET = 20;
152586
153211
  }
152587
153212
  });
@@ -152604,19 +153229,19 @@ function readTextIfExists(filePath) {
152604
153229
  }
152605
153230
  }
152606
153231
  function readPackageVersion(rootPath) {
152607
- const text = readTextIfExists(path26.join(rootPath, "package.json"));
152608
- if (!text) return void 0;
153232
+ const text2 = readTextIfExists(path26.join(rootPath, "package.json"));
153233
+ if (!text2) return void 0;
152609
153234
  try {
152610
- const parsed = JSON.parse(text);
153235
+ const parsed = JSON.parse(text2);
152611
153236
  return typeof parsed.version === "string" ? parsed.version : void 0;
152612
153237
  } catch {
152613
153238
  return void 0;
152614
153239
  }
152615
153240
  }
152616
153241
  function readLatestChangelog(rootPath) {
152617
- const text = readTextIfExists(path26.join(rootPath, "CHANGELOG.md"));
152618
- if (!text) return void 0;
152619
- const match2 = text.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
153242
+ const text2 = readTextIfExists(path26.join(rootPath, "CHANGELOG.md"));
153243
+ if (!text2) return void 0;
153244
+ const match2 = text2.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
152620
153245
  if (!match2) return void 0;
152621
153246
  return {
152622
153247
  version: match2[1],
@@ -152679,6 +153304,7 @@ function compareDateStrings(a, b) {
152679
153304
  }
152680
153305
  function detectStaleProgressNotes(input) {
152681
153306
  const candidates = [
153307
+ "ACTIVE_WORK.md",
152682
153308
  "progress.txt",
152683
153309
  "docs/dev-log/progress.txt",
152684
153310
  "docs/memcode/dev-log/progress.txt"
@@ -152816,6 +153442,7 @@ function providerQuality(input) {
152816
153442
  capabilities: {
152817
153443
  declarations: true,
152818
153444
  importHints: true,
153445
+ localRelativeImportTargets: true,
152819
153446
  resolvedRelations: false,
152820
153447
  exactLocations: false
152821
153448
  },
@@ -153337,8 +153964,8 @@ var compaction_checkpoint_store_exports = {};
153337
153964
  __export(compaction_checkpoint_store_exports, {
153338
153965
  CompactionCheckpointStore: () => CompactionCheckpointStore
153339
153966
  });
153340
- import { createHash as createHash14, randomUUID as randomUUID13 } from "crypto";
153341
- function optionalText6(value) {
153967
+ import { createHash as createHash14, randomUUID as randomUUID14 } from "crypto";
153968
+ function optionalText7(value) {
153342
153969
  return typeof value === "string" && value ? value : void 0;
153343
153970
  }
153344
153971
  function optionalNumber2(value) {
@@ -153392,15 +154019,15 @@ function rowToCheckpoint(row) {
153392
154019
  reason: row.reason,
153393
154020
  sourceEvent: row.source_event,
153394
154021
  sourceKey: row.source_key,
153395
- ...optionalText6(row.summary) ? { summary: row.summary } : {},
154022
+ ...optionalText7(row.summary) ? { summary: row.summary } : {},
153396
154023
  ...optionalNumber2(row.tokens_before) !== void 0 ? { tokensBefore: Number(row.tokens_before) } : {},
153397
- ...optionalText6(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
154024
+ ...optionalText7(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
153398
154025
  ...parseDetails(row.details_json) ? { details: parseDetails(row.details_json) } : {},
153399
154026
  transcriptAvailable: Boolean(row.transcript_available),
153400
154027
  status: row.status,
153401
154028
  preCapturedAt: row.pre_captured_at,
153402
- ...optionalText6(row.completed_at) ? { completedAt: row.completed_at } : {},
153403
- ...optionalText6(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
154029
+ ...optionalText7(row.completed_at) ? { completedAt: row.completed_at } : {},
154030
+ ...optionalText7(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
153404
154031
  deliveryCount: Number(row.delivery_count ?? 0),
153405
154032
  createdAt: row.created_at,
153406
154033
  updatedAt: row.updated_at
@@ -153438,7 +154065,7 @@ var init_compaction_checkpoint_store = __esm({
153438
154065
  if (pending) return rowToCheckpoint(pending);
153439
154066
  const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
153440
154067
  const checkpoint = {
153441
- id: randomUUID13(),
154068
+ id: randomUUID14(),
153442
154069
  projectId: input.projectId,
153443
154070
  sessionId: input.sessionId,
153444
154071
  agent: input.agent,
@@ -153446,7 +154073,7 @@ var init_compaction_checkpoint_store = __esm({
153446
154073
  captureKind: "preflight",
153447
154074
  reason: safeReason(input.reason),
153448
154075
  sourceEvent: input.sourceEvent,
153449
- sourceKey: `pre:${randomUUID13()}`,
154076
+ sourceKey: `pre:${randomUUID14()}`,
153450
154077
  transcriptAvailable: Boolean(input.transcriptAvailable),
153451
154078
  status: "active",
153452
154079
  preCapturedAt: now3,
@@ -153512,7 +154139,7 @@ var init_compaction_checkpoint_store = __esm({
153512
154139
  return this.get(checkpoint2.id);
153513
154140
  }
153514
154141
  const checkpoint = {
153515
- id: randomUUID13(),
154142
+ id: randomUUID14(),
153516
154143
  projectId: input.projectId,
153517
154144
  sessionId: input.sessionId,
153518
154145
  agent: input.agent,
@@ -153774,6 +154401,25 @@ async function buildAutoProjectContext(input) {
153774
154401
  const overview = explain.overview;
153775
154402
  const currentFacts = collectCurrentProjectFacts({ project: input.project, now: now3 });
153776
154403
  const latestSnapshot = overview.code.latestSnapshot;
154404
+ let codeEvolution;
154405
+ if (continuationRequested && latestSnapshot?.previousSnapshotId && latestSnapshot.changedPathCount > 0) {
154406
+ const diff = store.diffSnapshots(input.project.id, latestSnapshot.previousSnapshotId, latestSnapshot.id);
154407
+ if (diff.available && diff.changes.length > 0) {
154408
+ const impact = store.impactSlice(input.project.id, diff.changes.map((change) => change.path));
154409
+ const changedFileIds = new Set([
154410
+ ...store.listSnapshotFiles(diff.fromSnapshotId),
154411
+ ...store.listSnapshotFiles(diff.toSnapshotId)
154412
+ ].filter((file) => diff.changes.some((change) => change.path === file.path)).map((file) => file.fileId));
154413
+ codeEvolution = {
154414
+ fromSnapshotId: diff.fromSnapshotId,
154415
+ toSnapshotId: diff.toSnapshotId,
154416
+ changes: diff.changes.slice(0, 5).map((change) => ({ path: change.path, kind: change.kind })),
154417
+ directlyConnectedPaths: impact.directlyConnectedPaths.slice(0, 3),
154418
+ affectedMemoryCount: store.countStaleObservationRefsForFiles(input.project.id, [...changedFileIds]),
154419
+ truncated: impact.truncated || diff.changes.length > 5
154420
+ };
154421
+ }
154422
+ }
153777
154423
  const sourceSets = lensSourceSets({ task, lens, explain });
153778
154424
  let externalOutline;
153779
154425
  let externalCaution;
@@ -153850,6 +154496,7 @@ async function buildAutoProjectContext(input) {
153850
154496
  currentFacts: worksetFactLines(currentFacts),
153851
154497
  ...continuation ? { continuation } : {},
153852
154498
  codeState: codeStateLine(overview),
154499
+ ...codeEvolution ? { codeEvolution } : {},
153853
154500
  reliableMemory: sourceSets.reliableSources.slice(0, lens.sourceLimit).map((source) => ({
153854
154501
  id: source.observationId,
153855
154502
  title: source.title,
@@ -153901,9 +154548,9 @@ async function buildAutoProjectContext(input) {
153901
154548
  function formatLanguages(overview) {
153902
154549
  return overview.code.languages.length > 0 ? overview.code.languages.map((item) => `${item.language} ${item.files}`).join(", ") : "none indexed yet";
153903
154550
  }
153904
- function compactContinuationText(text, budget) {
154551
+ function compactContinuationText(text2, budget) {
153905
154552
  return truncateToTokenBudget(
153906
- sanitizeCredentials(text).replace(/\s+/g, " ").trim(),
154553
+ sanitizeCredentials(text2).replace(/\s+/g, " ").trim(),
153907
154554
  budget
153908
154555
  );
153909
154556
  }
@@ -154178,8 +154825,8 @@ __export(context_pack_exports, {
154178
154825
  function uniq2(items) {
154179
154826
  return [...new Set(items)];
154180
154827
  }
154181
- function tokenize4(text) {
154182
- return (text.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1);
154828
+ function tokenize4(text2) {
154829
+ return (text2.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1);
154183
154830
  }
154184
154831
  function timestampOf(observation) {
154185
154832
  return Date.parse(observation.updatedAt ?? observation.createdAt ?? "") || 0;
@@ -154781,7 +155428,7 @@ __export(team_store_exports, {
154781
155428
  isTeamStoreInitialized: () => isTeamStoreInitialized,
154782
155429
  resetTeamStore: () => resetTeamStore
154783
155430
  });
154784
- import { randomUUID as randomUUID14 } from "crypto";
155431
+ import { randomUUID as randomUUID15 } from "crypto";
154785
155432
  import path28 from "path";
154786
155433
  import fs18 from "fs";
154787
155434
  function getTeamStore() {
@@ -155070,7 +155717,7 @@ var init_team_store = __esm({
155070
155717
  * reactivate it (preserving agent_id). Otherwise create a new one.
155071
155718
  */
155072
155719
  registerAgent(input) {
155073
- const instanceId = input.instanceId || randomUUID14();
155720
+ const instanceId = input.instanceId || randomUUID15();
155074
155721
  const now3 = Date.now();
155075
155722
  const existing = this.stmtAgentFindByInstance.get(
155076
155723
  input.projectId,
@@ -155096,7 +155743,7 @@ var init_team_store = __esm({
155096
155743
  this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
155097
155744
  return row2;
155098
155745
  }
155099
- const agentId = randomUUID14();
155746
+ const agentId = randomUUID15();
155100
155747
  this.stmtAgentUpsert.run({
155101
155748
  agent_id: agentId,
155102
155749
  project_id: input.projectId,
@@ -155198,7 +155845,7 @@ var init_team_store = __esm({
155198
155845
  return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
155199
155846
  }
155200
155847
  }
155201
- const id = randomUUID14();
155848
+ const id = randomUUID15();
155202
155849
  const now3 = Date.now();
155203
155850
  const row = {
155204
155851
  id,
@@ -155248,7 +155895,7 @@ var init_team_store = __esm({
155248
155895
  // Task Operations (with atomic claim semantics)
155249
155896
  // ═══════════════════════════════════════════════════════════════════
155250
155897
  createTask(input) {
155251
- const taskId = randomUUID14();
155898
+ const taskId = randomUUID15();
155252
155899
  const now3 = Date.now();
155253
155900
  const row = {
155254
155901
  task_id: taskId,
@@ -155520,7 +156167,7 @@ var init_team_store = __esm({
155520
156167
  for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
155521
156168
  for (const msg of msgs) {
155522
156169
  this.stmtMsgInsert.run({
155523
- id: msg.id ?? randomUUID14(),
156170
+ id: msg.id ?? randomUUID15(),
155524
156171
  project_id: "migrated",
155525
156172
  sender_agent_id: msg.from ?? "unknown",
155526
156173
  recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
@@ -155793,19 +156440,19 @@ function buildCompactionWorkset(checkpoint, options = {}) {
155793
156440
  const source = sanitizeCredentials(checkpoint.summary?.trim() || fallback);
155794
156441
  const available = Math.max(0, budget - countTextTokens(header) - 4);
155795
156442
  let excerpt = source ? truncateToTokenBudget(source, available) : "";
155796
- let text = `${header}${excerpt ? `### Host checkpoint
156443
+ let text2 = `${header}${excerpt ? `### Host checkpoint
155797
156444
  ${excerpt}` : ""}`.trim();
155798
- while (excerpt && countTextTokens(text) > budget) {
156445
+ while (excerpt && countTextTokens(text2) > budget) {
155799
156446
  const nextExcerptBudget = Math.max(1, Math.floor(countTextTokens(excerpt) * 0.8));
155800
156447
  excerpt = truncateToTokenBudget(excerpt, nextExcerptBudget);
155801
- text = `${header}${excerpt ? `### Host checkpoint
156448
+ text2 = `${header}${excerpt ? `### Host checkpoint
155802
156449
  ${excerpt}` : ""}`.trim();
155803
156450
  }
155804
- if (countTextTokens(text) > budget) text = truncateToTokenBudget(text, budget);
156451
+ if (countTextTokens(text2) > budget) text2 = truncateToTokenBudget(text2, budget);
155805
156452
  return {
155806
156453
  checkpointId: checkpoint.id,
155807
- text,
155808
- tokens: countTextTokens(text)
156454
+ text: text2,
156455
+ tokens: countTextTokens(text2)
155809
156456
  };
155810
156457
  }
155811
156458
  function sourceEvent(input) {
@@ -157696,15 +158343,15 @@ function validateSemantics(graph) {
157696
158343
  return warnings;
157697
158344
  }
157698
158345
  function extractJson(raw) {
157699
- let text = raw;
158346
+ let text2 = raw;
157700
158347
  try {
157701
158348
  const envelope = JSON.parse(raw.trim());
157702
158349
  if (envelope && typeof envelope.result === "string" && envelope.type === "result") {
157703
- text = envelope.result;
158350
+ text2 = envelope.result;
157704
158351
  }
157705
158352
  } catch {
157706
158353
  }
157707
- if (text === raw && raw.includes('"type"')) {
158354
+ if (text2 === raw && raw.includes('"type"')) {
157708
158355
  const textBlocks = [];
157709
158356
  for (const line of raw.split("\n")) {
157710
158357
  const trimmed = line.trim();
@@ -157728,27 +158375,27 @@ function extractJson(raw) {
157728
158375
  }
157729
158376
  }
157730
158377
  if (textBlocks.length > 0) {
157731
- text = textBlocks.join("");
158378
+ text2 = textBlocks.join("");
157732
158379
  }
157733
158380
  }
157734
- const fenced = text.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
158381
+ const fenced = text2.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
157735
158382
  if (fenced) {
157736
158383
  const candidate = fenced[1].trim();
157737
158384
  if (candidate.startsWith("{")) return candidate;
157738
158385
  }
157739
- const braceStart = text.indexOf("{");
158386
+ const braceStart = text2.indexOf("{");
157740
158387
  if (braceStart !== -1) {
157741
- const extracted = extractBalancedJson(text, braceStart);
158388
+ const extracted = extractBalancedJson(text2, braceStart);
157742
158389
  if (extracted) return extracted;
157743
158390
  }
157744
158391
  return null;
157745
158392
  }
157746
- function extractBalancedJson(text, startIdx) {
158393
+ function extractBalancedJson(text2, startIdx) {
157747
158394
  let depth = 0;
157748
158395
  let inString = false;
157749
158396
  let escape2 = false;
157750
- for (let i2 = startIdx; i2 < text.length; i2++) {
157751
- const ch = text[i2];
158397
+ for (let i2 = startIdx; i2 < text2.length; i2++) {
158398
+ const ch = text2[i2];
157752
158399
  if (escape2) {
157753
158400
  escape2 = false;
157754
158401
  continue;
@@ -157766,7 +158413,7 @@ function extractBalancedJson(text, startIdx) {
157766
158413
  else if (ch === "}") {
157767
158414
  depth--;
157768
158415
  if (depth === 0) {
157769
- return text.slice(startIdx, i2 + 1);
158416
+ return text2.slice(startIdx, i2 + 1);
157770
158417
  }
157771
158418
  }
157772
158419
  }
@@ -157985,7 +158632,7 @@ __export(planner_exports, {
157985
158632
  materializeTaskGraph: () => materializeTaskGraph,
157986
158633
  seedAutonomousPipeline: () => seedAutonomousPipeline
157987
158634
  });
157988
- import { randomUUID as randomUUID15 } from "crypto";
158635
+ import { randomUUID as randomUUID16 } from "crypto";
157989
158636
  function isPlannerTask(metadata) {
157990
158637
  if (!metadata) return null;
157991
158638
  try {
@@ -158043,7 +158690,7 @@ function seedAutonomousPipeline(teamStore, projectId, config, opts) {
158043
158690
  const maxIterations = config.maxIterations ?? 3;
158044
158691
  const taskBudget = config.taskBudget ?? 15;
158045
158692
  const structuredPlan = opts?.structuredPlan ?? true;
158046
- const pipelineId = randomUUID15();
158693
+ const pipelineId = randomUUID16();
158047
158694
  const meta = {
158048
158695
  plannerType: "plan",
158049
158696
  pipelineId,
@@ -158488,8 +159135,8 @@ async function callVisionLLM(systemPrompt, imageBase64, mimeType) {
158488
159135
  return data.choices[0]?.message?.content ?? "";
158489
159136
  }
158490
159137
  function normalizeText4(value, fallback = "") {
158491
- const text = typeof value === "string" && value.trim() ? value.trim() : fallback;
158492
- return sanitizeCredentials(text).slice(0, MAX_VISION_DESCRIPTION_CHARS);
159138
+ const text2 = typeof value === "string" && value.trim() ? value.trim() : fallback;
159139
+ return sanitizeCredentials(text2).slice(0, MAX_VISION_DESCRIPTION_CHARS);
158493
159140
  }
158494
159141
  function normalizeLabels(value) {
158495
159142
  if (!Array.isArray(value)) return [];
@@ -161179,7 +161826,7 @@ function evidenceScore2(obs) {
161179
161826
  }
161180
161827
  function scoreForPacket(obs, queryTokens, referenceTime, broadMemoryQuery) {
161181
161828
  let score = 0;
161182
- const text = normalizeText3([
161829
+ const text2 = normalizeText3([
161183
161830
  obs.title,
161184
161831
  obs.narrative,
161185
161832
  obs.entityName,
@@ -161188,15 +161835,15 @@ function scoreForPacket(obs, queryTokens, referenceTime, broadMemoryQuery) {
161188
161835
  ...obs.relatedEntities ?? [],
161189
161836
  ...obs.relatedCommits ?? []
161190
161837
  ].join(" "));
161191
- const matchingTokens = queryTokens.filter((token) => text.includes(token));
161838
+ const matchingTokens = queryTokens.filter((token) => text2.includes(token));
161192
161839
  score += matchingTokens.length * 4;
161193
161840
  if (queryTokens.length > 0 && matchingTokens.length === 0) {
161194
161841
  score -= 8;
161195
161842
  }
161196
- if (broadMemoryQuery && /memorix|memcode|memory-(?:graph|injection|runtime|quality|formation)|graph-context/.test(text)) {
161843
+ if (broadMemoryQuery && /memorix|memcode|memory-(?:graph|injection|runtime|quality|formation)|graph-context/.test(text2)) {
161197
161844
  score += 8;
161198
161845
  }
161199
- if (/\bmemory[- ]?game\b|e2e-test\/memory-game|team-handoff/.test(text)) {
161846
+ if (/\bmemory[- ]?game\b|e2e-test\/memory-game|team-handoff/.test(text2)) {
161200
161847
  score -= broadMemoryQuery ? 12 : 4;
161201
161848
  }
161202
161849
  score += obs.valueCategory === "core" ? 6 : 0;
@@ -164129,7 +164776,7 @@ The path should point to a directory containing a .git folder.`
164129
164776
  };
164130
164777
  const server = existingServer ?? new McpServer({
164131
164778
  name: "memorix",
164132
- version: true ? "1.4.0" : "1.0.1"
164779
+ version: true ? "1.4.2" : "1.0.1"
164133
164780
  });
164134
164781
  const originalRegisterTool = server.registerTool.bind(server);
164135
164782
  server.registerTool = ((name, ...args) => {
@@ -164865,10 +165512,10 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
164865
165512
  const duplicate = blockCoveredAutopilotEvidence("memorix_search", result.entries.map((entry) => entry.id), force);
164866
165513
  if (duplicate) return duplicate;
164867
165514
  }
164868
- let text = result.formatted;
165515
+ let text2 = result.formatted;
164869
165516
  try {
164870
165517
  const { getLastSearchMode: getLastSearchMode2 } = await Promise.resolve().then(() => (init_orama_store(), orama_store_exports));
164871
- text += `
165518
+ text2 += `
164872
165519
 
164873
165520
  _Search mode: ${getLastSearchMode2(project.id)}_`;
164874
165521
  } catch {
@@ -164877,7 +165524,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
164877
165524
  content: [
164878
165525
  {
164879
165526
  type: "text",
164880
- text
165527
+ text: text2
164881
165528
  }
164882
165529
  ]
164883
165530
  };
@@ -164910,14 +165557,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
164910
165557
  query,
164911
165558
  limit: limit2 != null ? coerceNumber(limit2, 5) : void 0
164912
165559
  });
164913
- const text = format === "summary" ? [
165560
+ const text2 = format === "summary" ? [
164914
165561
  `Graph context packet for ${project.name}`,
164915
165562
  `- ${packet.summary}`,
164916
165563
  "",
164917
165564
  ...packet.entities.map((entity) => `* ${entity.name} (#${entity.observationIds.join(", #")})`)
164918
165565
  ].join("\n") : formatGraphContextPrompt(packet);
164919
165566
  return {
164920
- content: [{ type: "text", text }]
165567
+ content: [{ type: "text", text: text2 }]
164921
165568
  };
164922
165569
  }
164923
165570
  );
@@ -164977,7 +165624,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
164977
165624
  });
164978
165625
  }
164979
165626
  });
164980
- const text = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
165627
+ const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
164981
165628
  autopilotRetrievalBoundary = {
164982
165629
  projectId: project.id,
164983
165630
  issuedAt: Date.now(),
@@ -164989,7 +165636,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
164989
165636
  readOnly: READ_ONLY_TASK_PATTERN.test(task ?? "")
164990
165637
  };
164991
165638
  return {
164992
- content: [{ type: "text", text }]
165639
+ content: [{ type: "text", text: text2 }]
164993
165640
  };
164994
165641
  }
164995
165642
  );
@@ -165117,9 +165764,9 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165117
165764
  ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
165118
165765
  reader: getObservationReader()
165119
165766
  });
165120
- const text = buildContextPackPrompt2(pack);
165767
+ const text2 = buildContextPackPrompt2(pack);
165121
165768
  return {
165122
- content: [{ type: "text", text }]
165769
+ content: [{ type: "text", text: text2 }]
165123
165770
  };
165124
165771
  }
165125
165772
  );
@@ -165181,7 +165828,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165181
165828
  }) => {
165182
165829
  const unresolved = requireResolvedProject("manage the Knowledge Workspace for the current project");
165183
165830
  if (unresolved) return unresolved;
165184
- const text = (value, isError = false) => ({
165831
+ const text2 = (value, isError = false) => ({
165185
165832
  content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
165186
165833
  ...isError ? { isError: true } : {}
165187
165834
  });
@@ -165218,7 +165865,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165218
165865
  ]);
165219
165866
  if (action === "workspace_init") {
165220
165867
  if (modeValue === "versioned" && !requireText(workspacePath, "path")) {
165221
- return text({ error: "path is required to initialize a versioned Knowledge Workspace." }, true);
165868
+ return text2({ error: "path is required to initialize a versioned Knowledge Workspace." }, true);
165222
165869
  }
165223
165870
  const workspace2 = await initializeKnowledgeWorkspace2({
165224
165871
  projectId: project.id,
@@ -165226,7 +165873,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165226
165873
  mode: modeValue,
165227
165874
  ...modeValue === "versioned" ? { projectRoot: project.rootPath, rootPath: requireText(workspacePath, "path") } : {}
165228
165875
  });
165229
- return text({
165876
+ return text2({
165230
165877
  workspace: {
165231
165878
  id: workspace2.id,
165232
165879
  mode: workspace2.mode,
@@ -165238,7 +165885,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165238
165885
  }
165239
165886
  const workspace = await loadKnowledgeWorkspace2({ projectId: project.id, dataDir: projectDir2, mode: modeValue });
165240
165887
  if (!workspace) {
165241
- return text({ error: "Knowledge Workspace is not initialized. Run workspace_init first." }, true);
165888
+ return text2({ error: "Knowledge Workspace is not initialized. Run workspace_init first." }, true);
165242
165889
  }
165243
165890
  const claims = new ClaimStore2();
165244
165891
  const workspaceStore = new KnowledgeWorkspaceStore2();
@@ -165246,7 +165893,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165246
165893
  if (action === "status") {
165247
165894
  const pages = workspaceStore.listPages(workspace.id);
165248
165895
  const pending = workspaceStore.listProposals(workspace.id, "pending");
165249
- return text({
165896
+ return text2({
165250
165897
  workspace: {
165251
165898
  id: workspace.id,
165252
165899
  mode: workspace.mode,
@@ -165264,7 +165911,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165264
165911
  });
165265
165912
  }
165266
165913
  if (action === "claim_list") {
165267
- return text({
165914
+ return text2({
165268
165915
  claims: claims.listClaims(project.id, { limit: 100 }).map((claim) => ({
165269
165916
  id: claim.id,
165270
165917
  subject: claim.subject,
@@ -165283,18 +165930,18 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165283
165930
  const requestedClaimId = requireText(claimId, "claimId");
165284
165931
  const detail = requireText(reviewDetail, "reviewDetail");
165285
165932
  if (!requestedClaimId || !claimReviewState || !detail) {
165286
- return text({ error: "claimId, claimReviewState, and reviewDetail are required for claim_review." }, true);
165933
+ return text2({ error: "claimId, claimReviewState, and reviewDetail are required for claim_review." }, true);
165287
165934
  }
165288
165935
  const existing = claims.getClaim(requestedClaimId);
165289
165936
  if (!existing || existing.projectId !== project.id) {
165290
- return text({ error: "Claim was not found for the current project." }, true);
165937
+ return text2({ error: "Claim was not found for the current project." }, true);
165291
165938
  }
165292
165939
  const claim = reviewClaim2(claims, {
165293
165940
  claimId: requestedClaimId,
165294
165941
  reviewState: claimReviewState,
165295
165942
  detail
165296
165943
  });
165297
- return text({
165944
+ return text2({
165298
165945
  claim: {
165299
165946
  id: claim.id,
165300
165947
  status: claim.status,
@@ -165306,7 +165953,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165306
165953
  }
165307
165954
  if (action === "compile") {
165308
165955
  const result = await compileKnowledgeWorkspace2({ workspace, claims });
165309
- return text({
165956
+ return text2({
165310
165957
  proposals: result.proposals.map((proposal) => ({
165311
165958
  id: proposal.id,
165312
165959
  targetPath: proposal.targetPath,
@@ -165321,17 +165968,17 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165321
165968
  const codeStore = new CodeGraphStore2();
165322
165969
  await codeStore.init(projectDir2);
165323
165970
  const result = await lintKnowledgeWorkspace2({ workspace, claims, codeStore });
165324
- return text(result);
165971
+ return text2(result);
165325
165972
  }
165326
165973
  if (action === "proposal_apply") {
165327
165974
  const proposal = requireText(proposalId, "proposalId");
165328
- if (!proposal) return text({ error: "proposalId is required for proposal_apply." }, true);
165975
+ if (!proposal) return text2({ error: "proposalId is required for proposal_apply." }, true);
165329
165976
  const result = await applyKnowledgeProposal2({
165330
165977
  workspace,
165331
165978
  proposalId: proposal,
165332
165979
  allowManualOverwrite: !!allowManualOverwrite
165333
165980
  });
165334
- return text({
165981
+ return text2({
165335
165982
  proposal: { id: result.proposal.id, status: result.proposal.status },
165336
165983
  targetPath: result.targetPath
165337
165984
  });
@@ -165341,7 +165988,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165341
165988
  const projectRoot = workspace.projectRoot ?? project.rootPath;
165342
165989
  if (action === "workflow_import") {
165343
165990
  const result = await importWindsurfWorkflows2({ workspace, projectRoot });
165344
- return text({
165991
+ return text2({
165345
165992
  imported: result.imported.map((workflow2) => ({
165346
165993
  id: workflow2.id,
165347
165994
  title: workflow2.title,
@@ -165354,7 +166001,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165354
166001
  }
165355
166002
  const synced = await syncCanonicalWorkflows2(workspace);
165356
166003
  if (action === "workflow_list") {
165357
- return text({
166004
+ return text2({
165358
166005
  workflows: workflowStore.listWorkflows(workspace.id).map((workflow2) => ({
165359
166006
  id: workflow2.id,
165360
166007
  title: workflow2.title,
@@ -165369,9 +166016,9 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165369
166016
  }
165370
166017
  if (action === "workflow_select") {
165371
166018
  const selectedTask = requireText(task, "task");
165372
- if (!selectedTask) return text({ error: "task is required for workflow_select." }, true);
166019
+ if (!selectedTask) return text2({ error: "task is required for workflow_select." }, true);
165373
166020
  const result = await selectWorkspaceWorkflows2({ workspace, task: selectedTask });
165374
- return text({
166021
+ return text2({
165375
166022
  selections: result.selections.map((selection) => ({
165376
166023
  id: selection.workflow.id,
165377
166024
  title: selection.workflow.title,
@@ -165383,16 +166030,16 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165383
166030
  });
165384
166031
  }
165385
166032
  const requestedWorkflowId = requireText(workflowId, "workflowId");
165386
- if (!requestedWorkflowId) return text({ error: "workflowId is required for this workflow action." }, true);
166033
+ if (!requestedWorkflowId) return text2({ error: "workflowId is required for this workflow action." }, true);
165387
166034
  const workflow = workflowStore.getWorkflow(requestedWorkflowId);
165388
166035
  if (!workflow || workflow.workspaceId !== workspace.id) {
165389
- return text({ error: "Workflow was not found for this Knowledge Workspace." }, true);
166036
+ return text2({ error: "Workflow was not found for this Knowledge Workspace." }, true);
165390
166037
  }
165391
166038
  if (action === "workflow_preview" || action === "workflow_apply") {
165392
166039
  const targetAgent = requireText(agent, "agent");
165393
- if (!targetAgent) return text({ error: "agent is required for a workflow adapter action." }, true);
166040
+ if (!targetAgent) return text2({ error: "agent is required for a workflow adapter action." }, true);
165394
166041
  const result = action === "workflow_preview" ? await previewWorkflowAdapter2({ workflow, projectRoot, agent: targetAgent }) : await applyWorkflowAdapter2({ workflow, projectRoot, agent: targetAgent });
165395
- return text({
166042
+ return text2({
165396
166043
  workflowId: workflow.id,
165397
166044
  agent: targetAgent,
165398
166045
  status: result.status,
@@ -165403,8 +166050,8 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165403
166050
  }
165404
166051
  if (action === "workflow_run") {
165405
166052
  const runTask = requireText(task, "task");
165406
- if (!runTask) return text({ error: "task is required for workflow_run." }, true);
165407
- if (!outcome) return text({ error: "outcome is required for workflow_run." }, true);
166053
+ if (!runTask) return text2({ error: "task is required for workflow_run." }, true);
166054
+ if (!outcome) return text2({ error: "outcome is required for workflow_run." }, true);
165408
166055
  const result = await recordWorkflowRun2({
165409
166056
  workspace,
165410
166057
  run: {
@@ -165418,14 +166065,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165418
166065
  selectedEvidence: [...new Set((evidenceIds ?? []).map((item) => item.trim()).filter(Boolean))]
165419
166066
  }
165420
166067
  });
165421
- return text({
166068
+ return text2({
165422
166069
  id: result.id,
165423
166070
  workflowId: result.workflowId,
165424
166071
  outcome: result.outcome,
165425
166072
  verificationVerdict: result.verificationVerdict
165426
166073
  });
165427
166074
  }
165428
- return text({ error: "Unsupported knowledge action." }, true);
166075
+ return text2({ error: "Unsupported knowledge action." }, true);
165429
166076
  }
165430
166077
  );
165431
166078
  server.registerTool(
@@ -166900,10 +167547,10 @@ Ensure the path points to a directory containing a .git folder (or a subdirector
166900
167547
  ];
166901
167548
  const allSkills = await loadMiniSkills2(projectDir2, project.id);
166902
167549
  const miniSkills = allSkills.filter((s2) => {
166903
- const text = `${s2.title}
167550
+ const text2 = `${s2.title}
166904
167551
  ${s2.sourceEntity}
166905
167552
  ${s2.instruction}`.toLowerCase();
166906
- return !SKILL_NOISE.some((p) => p.test(text));
167553
+ return !SKILL_NOISE.some((p) => p.test(text2));
166907
167554
  });
166908
167555
  if (miniSkills.length > 0) {
166909
167556
  const formatted = formatMiniSkillsForInjection2(miniSkills);