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/index.js CHANGED
@@ -312,7 +312,7 @@ function closeAllDatabases() {
312
312
  _dbCache.delete(key);
313
313
  }
314
314
  }
315
- 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;
315
+ 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;
316
316
  var init_sqlite_db = __esm({
317
317
  "src/store/sqlite-db.ts"() {
318
318
  "use strict";
@@ -578,6 +578,17 @@ CREATE TABLE IF NOT EXISTS observation_code_refs (
578
578
  " UNIQUE(projectId, sourceEpoch)",
579
579
  ");"
580
580
  ].join("\n");
581
+ CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE = [
582
+ "CREATE TABLE IF NOT EXISTS code_state_snapshot_files (",
583
+ " snapshotId TEXT NOT NULL,",
584
+ " projectId TEXT NOT NULL,",
585
+ " fileId TEXT NOT NULL,",
586
+ " path TEXT NOT NULL,",
587
+ " contentHash TEXT NOT NULL,",
588
+ " PRIMARY KEY (snapshotId, path),",
589
+ " FOREIGN KEY (snapshotId) REFERENCES code_state_snapshots(id) ON DELETE CASCADE",
590
+ ");"
591
+ ].join("\n");
581
592
  CREATE_KNOWLEDGE_CLAIMS_TABLE = `
582
593
  CREATE TABLE IF NOT EXISTS knowledge_claims (
583
594
  id TEXT PRIMARY KEY,
@@ -788,6 +799,19 @@ CREATE TABLE IF NOT EXISTS long_term_memory_events (
788
799
  createdAt TEXT NOT NULL,
789
800
  FOREIGN KEY (memoryId) REFERENCES long_term_memories(id) ON DELETE CASCADE
790
801
  );
802
+ `;
803
+ CREATE_MEMORY_OUTCOME_SIGNALS_TABLE = `
804
+ CREATE TABLE IF NOT EXISTS memory_outcome_signals (
805
+ id TEXT PRIMARY KEY,
806
+ projectId TEXT NOT NULL,
807
+ candidateKind TEXT NOT NULL,
808
+ candidateId TEXT NOT NULL,
809
+ kind TEXT NOT NULL,
810
+ sourceRef TEXT NOT NULL,
811
+ snapshotId TEXT,
812
+ detail TEXT,
813
+ observedAt TEXT NOT NULL
814
+ );
791
815
  `;
792
816
  CREATE_MEDIA_ASSETS_TABLE = `
793
817
  CREATE TABLE IF NOT EXISTS media_assets (
@@ -1030,6 +1054,20 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1030
1054
  db2.exec("CREATE INDEX IF NOT EXISTS idx_code_edges_snapshot ON code_edges(projectId, snapshotId)");
1031
1055
  }
1032
1056
  },
1057
+ {
1058
+ id: "1.4-codegraph-snapshot-manifest",
1059
+ apply: (db2) => {
1060
+ db2.exec(CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE);
1061
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_code_snapshot_files_project_path ON code_state_snapshot_files(projectId, path)");
1062
+ }
1063
+ },
1064
+ {
1065
+ id: "1.4-memory-outcome-signals",
1066
+ apply: (db2) => {
1067
+ db2.exec(CREATE_MEMORY_OUTCOME_SIGNALS_TABLE);
1068
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_outcomes_candidate ON memory_outcome_signals(projectId, candidateKind, candidateId, observedAt DESC)");
1069
+ }
1070
+ },
1033
1071
  {
1034
1072
  id: "1.2-knowledge-claim-ledger",
1035
1073
  apply: (db2) => {
@@ -2224,17 +2262,17 @@ var init_mini_skill_store = __esm({
2224
2262
 
2225
2263
  // src/compact/token-budget.ts
2226
2264
  import { countTokens, isWithinTokenLimit } from "gpt-tokenizer";
2227
- function countTextTokens(text) {
2228
- return countTokens(text);
2265
+ function countTextTokens(text2) {
2266
+ return countTokens(text2);
2229
2267
  }
2230
- function fitsInBudget(text, limit2) {
2231
- return isWithinTokenLimit(text, limit2);
2268
+ function fitsInBudget(text2, limit2) {
2269
+ return isWithinTokenLimit(text2, limit2);
2232
2270
  }
2233
- function truncateToTokenBudget(text, budget) {
2234
- if (fitsInBudget(text, budget) !== false) {
2235
- return text;
2271
+ function truncateToTokenBudget(text2, budget) {
2272
+ if (fitsInBudget(text2, budget) !== false) {
2273
+ return text2;
2236
2274
  }
2237
- const sentences = text.split(/(?<=[.!?])\s+/);
2275
+ const sentences = text2.split(/(?<=[.!?])\s+/);
2238
2276
  let result = "";
2239
2277
  for (const sentence of sentences) {
2240
2278
  const candidate = result ? `${result} ${sentence}` : sentence;
@@ -2245,12 +2283,12 @@ function truncateToTokenBudget(text, budget) {
2245
2283
  }
2246
2284
  if (!result) {
2247
2285
  const estimatedChars = budget * 2;
2248
- result = text.slice(0, estimatedChars);
2286
+ result = text2.slice(0, estimatedChars);
2249
2287
  while (fitsInBudget(result, budget) === false && result.length > 0) {
2250
2288
  result = result.slice(0, Math.floor(result.length * 0.9));
2251
2289
  }
2252
- if (result.length < text.length) {
2253
- const nextCharacter = text.charAt(result.length);
2290
+ if (result.length < text2.length) {
2291
+ const nextCharacter = text2.charAt(result.length);
2254
2292
  if (nextCharacter && !/[\s.,;:!?)}\]]/.test(nextCharacter)) {
2255
2293
  const boundary = result.search(/\s+\S*$/);
2256
2294
  result = boundary > 0 ? result.slice(0, boundary).trimEnd() : "";
@@ -3434,8 +3472,8 @@ import { createHash } from "crypto";
3434
3472
  import { readFile, writeFile, mkdir } from "fs/promises";
3435
3473
  import { join as join2 } from "path";
3436
3474
  import { homedir as homedir6 } from "os";
3437
- function textHash(text) {
3438
- return createHash("sha256").update(text).digest("hex").slice(0, 16);
3475
+ function textHash(text2) {
3476
+ return createHash("sha256").update(text2).digest("hex").slice(0, 16);
3439
3477
  }
3440
3478
  async function loadDiskCache() {
3441
3479
  try {
@@ -3498,11 +3536,11 @@ var init_fastembed_provider = __esm({
3498
3536
  async embedInputs(inputs, options = {}) {
3499
3537
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
3500
3538
  }
3501
- async embed(text) {
3502
- const hash4 = textHash(text);
3539
+ async embed(text2) {
3540
+ const hash4 = textHash(text2);
3503
3541
  const cached = cache.get(hash4);
3504
3542
  if (cached) return cached;
3505
- const raw = await this.model.queryEmbed(text);
3543
+ const raw = await this.model.queryEmbed(text2);
3506
3544
  const result = Array.from(raw);
3507
3545
  if (result.length !== this.dimensions) {
3508
3546
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
@@ -3598,10 +3636,10 @@ var init_transformers_provider = __esm({
3598
3636
  async embedInputs(inputs, options = {}) {
3599
3637
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
3600
3638
  }
3601
- async embed(text) {
3602
- const cached = cache2.get(text);
3639
+ async embed(text2) {
3640
+ const cached = cache2.get(text2);
3603
3641
  if (cached) return cached;
3604
- const output = await this.extractor(text, {
3642
+ const output = await this.extractor(text2, {
3605
3643
  pooling: "mean",
3606
3644
  normalize: true
3607
3645
  });
@@ -3609,7 +3647,7 @@ var init_transformers_provider = __esm({
3609
3647
  if (result.length !== this.dimensions) {
3610
3648
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
3611
3649
  }
3612
- this.cacheSet(text, result);
3650
+ this.cacheSet(text2, result);
3613
3651
  return result;
3614
3652
  }
3615
3653
  async embedBatch(texts) {
@@ -3672,8 +3710,8 @@ function dimsCacheFile() {
3672
3710
  function cacheMetaFile() {
3673
3711
  return join3(cacheDir(), ".embedding-api-cache-meta.json");
3674
3712
  }
3675
- function normalizeText(text) {
3676
- return text.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
3713
+ function normalizeText(text2) {
3714
+ return text2.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
3677
3715
  }
3678
3716
  function cacheNamespace(config) {
3679
3717
  return [
@@ -3683,8 +3721,8 @@ function cacheNamespace(config) {
3683
3721
  config.requestedDimensions ?? "native"
3684
3722
  ].join("|");
3685
3723
  }
3686
- function textHash2(text, namespace) {
3687
- return createHash2("sha256").update(`${namespace}\0${text}`).digest("hex").slice(0, 16);
3724
+ function textHash2(text2, namespace) {
3725
+ return createHash2("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
3688
3726
  }
3689
3727
  function inputIdentity(input, options = {}) {
3690
3728
  return JSON.stringify({
@@ -4096,8 +4134,8 @@ var init_api_provider = __esm({
4096
4134
  if (!embedding) throw new Error("API probe returned no embeddings; check model name and API key");
4097
4135
  return embedding.length;
4098
4136
  }
4099
- async embed(text, options) {
4100
- const normalized = normalizeText(text);
4137
+ async embed(text2, options) {
4138
+ const normalized = normalizeText(text2);
4101
4139
  if (isNativeGeminiEndpoint(this.config.baseUrl)) {
4102
4140
  return this.embedInput({ modality: "text", text: normalized }, { intent: "document", ...options });
4103
4141
  }
@@ -4154,7 +4192,7 @@ var init_api_provider = __esm({
4154
4192
  }
4155
4193
  async embedBatch(texts, options) {
4156
4194
  if (isNativeGeminiEndpoint(this.config.baseUrl)) {
4157
- return Promise.all(texts.map((text) => this.embedInput({ modality: "text", text }, { intent: "document", ...options })));
4195
+ return Promise.all(texts.map((text2) => this.embedInput({ modality: "text", text: text2 }, { intent: "document", ...options })));
4158
4196
  }
4159
4197
  await ensureDiskCacheLoaded();
4160
4198
  const normalizedTexts = texts.map(normalizeText);
@@ -4233,8 +4271,8 @@ var init_api_provider = __esm({
4233
4271
  }
4234
4272
  async getCachedEmbeddings(texts) {
4235
4273
  await ensureDiskCacheLoaded();
4236
- return texts.map((text) => {
4237
- const hash4 = textHash2(normalizeText(text), this.cacheKeyNamespace);
4274
+ return texts.map((text2) => {
4275
+ const hash4 = textHash2(normalizeText(text2), this.cacheKeyNamespace);
4238
4276
  return cache3.get(hash4) ?? null;
4239
4277
  });
4240
4278
  }
@@ -4464,9 +4502,9 @@ function wrapProvider(candidate) {
4464
4502
  return {
4465
4503
  name: candidate.name,
4466
4504
  dimensions: candidate.dimensions,
4467
- async embed(text, options) {
4505
+ async embed(text2, options) {
4468
4506
  try {
4469
- return await candidate.embed(text, options);
4507
+ return await candidate.embed(text2, options);
4470
4508
  } catch (error) {
4471
4509
  if (kind === "api" && getEmbeddingMode2() === "auto" && isTemporaryEmbeddingFailure(error)) {
4472
4510
  warnOnce("[memorix] API embedding temporarily unavailable \u2014 switching to local fallback provider");
@@ -4474,7 +4512,7 @@ function wrapProvider(candidate) {
4474
4512
  if (fallback) {
4475
4513
  provider = wrapProvider(fallback);
4476
4514
  warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);
4477
- return provider.embed(text, options);
4515
+ return provider.embed(text2, options);
4478
4516
  }
4479
4517
  }
4480
4518
  if (isTemporaryEmbeddingFailure(error)) {
@@ -5033,8 +5071,8 @@ async function readResponseText(response, signal, maxBytes = MAX_LLM_RESPONSE_BY
5033
5071
  }
5034
5072
  }
5035
5073
  async function readResponseJson(response, signal, maxBytes = MAX_LLM_RESPONSE_BYTES) {
5036
- const text = await readResponseText(response, signal, maxBytes);
5037
- return JSON.parse(text);
5074
+ const text2 = await readResponseText(response, signal, maxBytes);
5075
+ return JSON.parse(text2);
5038
5076
  }
5039
5077
  async function* callLLMWithToolsStream(messages, tools) {
5040
5078
  if (!currentConfig) {
@@ -5587,8 +5625,8 @@ function isCjkHeavy(query) {
5587
5625
  const cjkCount = (query.match(CJK_PATTERN) || []).length;
5588
5626
  return query.length > 0 && cjkCount / query.length > 0.3;
5589
5627
  }
5590
- function normalizeExpansion(text) {
5591
- return text.trim().replace(/^[-*]\s*/, "").replace(/^["'`]+|["'`]+$/g, "").split(/\r?\n/)[0].trim();
5628
+ function normalizeExpansion(text2) {
5629
+ return text2.trim().replace(/^[-*]\s*/, "").replace(/^["'`]+|["'`]+$/g, "").split(/\r?\n/)[0].trim();
5592
5630
  }
5593
5631
  async function maybeExpandSearchQuery(query) {
5594
5632
  if (!query || !isCjkHeavy(query) || COMMAND_LIKE_QUERY.test(query)) {
@@ -5951,9 +5989,9 @@ function shouldSkipCompression(narrative, type) {
5951
5989
  if (specialChars / narrative.length > 0.35) return true;
5952
5990
  return false;
5953
5991
  }
5954
- function estimateTokens(text) {
5955
- const cjkChars = (text.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length;
5956
- const otherChars = text.length - cjkChars;
5992
+ function estimateTokens(text2) {
5993
+ const cjkChars = (text2.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length;
5994
+ const otherChars = text2.length - cjkChars;
5957
5995
  return Math.ceil(cjkChars / 1.5 + otherChars / 4);
5958
5996
  }
5959
5997
  var COMPRESS_PROMPT, COMPRESS_PROMPT_GENTLE, RERANK_PROMPT, SKIP_PATTERNS, LOW_COMPRESSION_TYPES;
@@ -6256,10 +6294,10 @@ function isEmbeddingEnabled() {
6256
6294
  function getVectorDimensions() {
6257
6295
  return embeddingEnabled ? embeddingDimensions : null;
6258
6296
  }
6259
- async function generateEmbedding(text) {
6297
+ async function generateEmbedding(text2) {
6260
6298
  const provider2 = await getEmbeddingProvider();
6261
6299
  if (!provider2) return null;
6262
- return provider2.embedInput ? provider2.embedInput({ modality: "text", text }, { intent: "document" }) : provider2.embed(text);
6300
+ return provider2.embedInput ? provider2.embedInput({ modality: "text", text: text2 }, { intent: "document" }) : provider2.embed(text2);
6263
6301
  }
6264
6302
  async function generateEmbeddingInput(input, options = {}) {
6265
6303
  const provider2 = await getEmbeddingProvider();
@@ -7591,9 +7629,9 @@ var init_entity_extractor = __esm({
7591
7629
  });
7592
7630
 
7593
7631
  // src/memory/secret-filter.ts
7594
- function applyRedaction(text) {
7595
- if (!text) return text;
7596
- let out = text;
7632
+ function applyRedaction(text2) {
7633
+ if (!text2) return text2;
7634
+ let out = text2;
7597
7635
  out = out.replace(
7598
7636
  /((?:password|passwd|pwd|secret|token|api[_-]?key|auth[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret)\s*[:=]\s*["']?)([^\s"',;\n]{6,})/gi,
7599
7637
  "$1[REDACTED]"
@@ -7607,11 +7645,11 @@ function applyRedaction(text) {
7607
7645
  out = out.replace(/\beyJ[A-Za-z0-9._-]{40,}\b/g, "[REDACTED]");
7608
7646
  return out;
7609
7647
  }
7610
- function sanitizeCredentials(text) {
7611
- return applyRedaction(text);
7648
+ function sanitizeCredentials(text2) {
7649
+ return applyRedaction(text2);
7612
7650
  }
7613
- function redactCredentials(text) {
7614
- return applyRedaction(text);
7651
+ function redactCredentials(text2) {
7652
+ return applyRedaction(text2);
7615
7653
  }
7616
7654
  var init_secret_filter = __esm({
7617
7655
  "src/memory/secret-filter.ts"() {
@@ -7662,8 +7700,8 @@ function clampPositiveInteger(value, fallback) {
7662
7700
  return Math.max(1, Math.floor(value));
7663
7701
  }
7664
7702
  function errorText(error) {
7665
- const text = error instanceof Error ? error.message : String(error);
7666
- return sanitizeCredentials(text).slice(0, MAX_ERROR_LENGTH);
7703
+ const text2 = error instanceof Error ? error.message : String(error);
7704
+ return sanitizeCredentials(text2).slice(0, MAX_ERROR_LENGTH);
7667
7705
  }
7668
7706
  function normalizedKinds(kinds) {
7669
7707
  if (!kinds) return void 0;
@@ -8757,9 +8795,9 @@ __export(consolidation_exports, {
8757
8795
  executeConsolidation: () => executeConsolidation,
8758
8796
  findConsolidationCandidates: () => findConsolidationCandidates
8759
8797
  });
8760
- function tokenize(text) {
8798
+ function tokenize(text2) {
8761
8799
  return new Set(
8762
- text.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff\s-]/g, " ").split(/\s+/).filter((t2) => t2.length > 1)
8800
+ text2.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff\s-]/g, " ").split(/\s+/).filter((t2) => t2.length > 1)
8763
8801
  );
8764
8802
  }
8765
8803
  function jaccardSimilarity(a, b) {
@@ -17911,8 +17949,8 @@ var init_headers = __esm({
17911
17949
  });
17912
17950
 
17913
17951
  // packages/ai/dist/utils/sanitize-unicode.js
17914
- function sanitizeSurrogates(text) {
17915
- return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
17952
+ function sanitizeSurrogates(text2) {
17953
+ return text2.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
17916
17954
  }
17917
17955
  var init_sanitize_unicode = __esm({
17918
17956
  "packages/ai/dist/utils/sanitize-unicode.js"() {
@@ -18394,9 +18432,9 @@ var init_values = __esm({
18394
18432
  }
18395
18433
  return n;
18396
18434
  };
18397
- safeJSON = (text) => {
18435
+ safeJSON = (text2) => {
18398
18436
  try {
18399
- return JSON.parse(text);
18437
+ return JSON.parse(text2);
18400
18438
  } catch (err) {
18401
18439
  return void 0;
18402
18440
  }
@@ -19559,8 +19597,8 @@ async function defaultParseResponse(client, props) {
19559
19597
  const json2 = await response.json();
19560
19598
  return addRequestID(json2, response);
19561
19599
  }
19562
- const text = await response.text();
19563
- return text;
19600
+ const text2 = await response.text();
19601
+ return text2;
19564
19602
  })();
19565
19603
  loggerFor(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails({
19566
19604
  retryOfRequestLogID,
@@ -32930,7 +32968,7 @@ var init_models_generated = __esm({
32930
32968
  provider: "minimax",
32931
32969
  baseUrl: "https://api.minimax.io/anthropic",
32932
32970
  reasoning: true,
32933
- input: ["text", "image"],
32971
+ input: ["text", "image", "video"],
32934
32972
  cost: {
32935
32973
  input: 0.3,
32936
32974
  output: 1.2,
@@ -32983,7 +33021,7 @@ var init_models_generated = __esm({
32983
33021
  provider: "minimax-cn",
32984
33022
  baseUrl: "https://api.minimaxi.com/anthropic",
32985
33023
  reasoning: true,
32986
- input: ["text", "image"],
33024
+ input: ["text", "image", "video"],
32987
33025
  cost: {
32988
33026
  input: 0.3,
32989
33027
  output: 1.2,
@@ -45178,9 +45216,9 @@ var init_values2 = __esm({
45178
45216
  }
45179
45217
  return n;
45180
45218
  };
45181
- safeJSON2 = (text) => {
45219
+ safeJSON2 = (text2) => {
45182
45220
  try {
45183
- return JSON.parse(text);
45221
+ return JSON.parse(text2);
45184
45222
  } catch (err) {
45185
45223
  return void 0;
45186
45224
  }
@@ -45954,8 +45992,8 @@ async function defaultParseResponse2(client, props) {
45954
45992
  const json2 = await response.json();
45955
45993
  return addRequestID2(json2, response);
45956
45994
  }
45957
- const text = await response.text();
45958
- return text;
45995
+ const text2 = await response.text();
45996
+ return text2;
45959
45997
  })();
45960
45998
  loggerFor2(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails2({
45961
45999
  retryOfRequestLogID,
@@ -52258,11 +52296,11 @@ var init_simple_options = __esm({
52258
52296
  });
52259
52297
 
52260
52298
  // packages/ai/dist/providers/transform-messages.js
52261
- function replaceImagesWithPlaceholder(content, placeholder) {
52299
+ function replaceMediaWithPlaceholder(content, dropType, placeholder) {
52262
52300
  const result = [];
52263
52301
  let previousWasPlaceholder = false;
52264
52302
  for (const block of content) {
52265
- if (block.type === "image") {
52303
+ if (block.type === dropType) {
52266
52304
  if (!previousWasPlaceholder) {
52267
52305
  result.push({ type: "text", text: placeholder });
52268
52306
  }
@@ -52270,33 +52308,39 @@ function replaceImagesWithPlaceholder(content, placeholder) {
52270
52308
  continue;
52271
52309
  }
52272
52310
  result.push(block);
52273
- previousWasPlaceholder = block.text === placeholder;
52311
+ previousWasPlaceholder = block.type === "text" && block.text === placeholder;
52274
52312
  }
52275
52313
  return result;
52276
52314
  }
52277
- function downgradeUnsupportedImages(messages, model) {
52278
- if (model.input.includes("image")) {
52315
+ function downgradeUnsupportedMedia(messages, model) {
52316
+ const supportsImage = model.input.includes("image");
52317
+ const supportsVideo = model.input.includes("video");
52318
+ if (supportsImage && supportsVideo) {
52279
52319
  return messages;
52280
52320
  }
52281
52321
  return messages.map((msg) => {
52282
52322
  if (msg.role === "user" && Array.isArray(msg.content)) {
52283
- return {
52284
- ...msg,
52285
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER)
52286
- };
52323
+ let content = msg.content;
52324
+ if (!supportsImage)
52325
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_USER_IMAGE_PLACEHOLDER);
52326
+ if (!supportsVideo)
52327
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_USER_VIDEO_PLACEHOLDER);
52328
+ return { ...msg, content };
52287
52329
  }
52288
52330
  if (msg.role === "toolResult") {
52289
- return {
52290
- ...msg,
52291
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)
52292
- };
52331
+ let content = msg.content;
52332
+ if (!supportsImage)
52333
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_TOOL_IMAGE_PLACEHOLDER);
52334
+ if (!supportsVideo)
52335
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_TOOL_VIDEO_PLACEHOLDER);
52336
+ return { ...msg, content };
52293
52337
  }
52294
52338
  return msg;
52295
52339
  });
52296
52340
  }
52297
52341
  function transformMessages(messages, model, normalizeToolCallId2) {
52298
52342
  const toolCallIdMap = /* @__PURE__ */ new Map();
52299
- const imageAwareMessages = downgradeUnsupportedImages(messages, model);
52343
+ const imageAwareMessages = downgradeUnsupportedMedia(messages, model);
52300
52344
  const transformed = imageAwareMessages.map((msg) => {
52301
52345
  if (msg.role === "user") {
52302
52346
  return msg;
@@ -52408,13 +52452,15 @@ function transformMessages(messages, model, normalizeToolCallId2) {
52408
52452
  insertSyntheticToolResults();
52409
52453
  return result;
52410
52454
  }
52411
- var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER;
52455
+ var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER, NON_VISION_USER_VIDEO_PLACEHOLDER, NON_VISION_TOOL_VIDEO_PLACEHOLDER;
52412
52456
  var init_transform_messages = __esm({
52413
52457
  "packages/ai/dist/providers/transform-messages.js"() {
52414
52458
  "use strict";
52415
52459
  init_esm_shims();
52416
52460
  NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
52417
52461
  NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
52462
+ NON_VISION_USER_VIDEO_PLACEHOLDER = "(video omitted: model does not support video)";
52463
+ NON_VISION_TOOL_VIDEO_PLACEHOLDER = "(tool video omitted: model does not support video)";
52418
52464
  }
52419
52465
  });
52420
52466
 
@@ -52445,8 +52491,8 @@ function getCacheControl(model, cacheRetention) {
52445
52491
  };
52446
52492
  }
52447
52493
  function convertContentBlocks(content) {
52448
- const hasImages = content.some((c) => c.type === "image");
52449
- if (!hasImages) {
52494
+ const hasMedia = content.some((c) => c.type === "image" || c.type === "video");
52495
+ if (!hasMedia) {
52450
52496
  return sanitizeSurrogates(content.map((c) => c.text).join("\n"));
52451
52497
  }
52452
52498
  const blocks = content.map((block) => {
@@ -52456,6 +52502,16 @@ function convertContentBlocks(content) {
52456
52502
  text: sanitizeSurrogates(block.text)
52457
52503
  };
52458
52504
  }
52505
+ if (block.type === "video") {
52506
+ return {
52507
+ type: "video",
52508
+ source: {
52509
+ type: "base64",
52510
+ media_type: block.mimeType,
52511
+ data: block.data
52512
+ }
52513
+ };
52514
+ }
52459
52515
  return {
52460
52516
  type: "image",
52461
52517
  source: {
@@ -52469,7 +52525,7 @@ function convertContentBlocks(content) {
52469
52525
  if (!hasText) {
52470
52526
  blocks.unshift({
52471
52527
  type: "text",
52472
- text: "(see attached image)"
52528
+ text: "(see attached media)"
52473
52529
  });
52474
52530
  }
52475
52531
  return blocks;
@@ -52530,9 +52586,9 @@ function decodeSseLine(line, state) {
52530
52586
  }
52531
52587
  return null;
52532
52588
  }
52533
- function nextLineBreakIndex(text) {
52534
- const carriageReturnIndex = text.indexOf("\r");
52535
- const newlineIndex = text.indexOf("\n");
52589
+ function nextLineBreakIndex(text2) {
52590
+ const carriageReturnIndex = text2.indexOf("\r");
52591
+ const newlineIndex = text2.indexOf("\n");
52536
52592
  if (carriageReturnIndex === -1) {
52537
52593
  return newlineIndex;
52538
52594
  }
@@ -52541,18 +52597,18 @@ function nextLineBreakIndex(text) {
52541
52597
  }
52542
52598
  return Math.min(carriageReturnIndex, newlineIndex);
52543
52599
  }
52544
- function consumeLine(text) {
52545
- const lineBreakIndex = nextLineBreakIndex(text);
52600
+ function consumeLine(text2) {
52601
+ const lineBreakIndex = nextLineBreakIndex(text2);
52546
52602
  if (lineBreakIndex === -1) {
52547
52603
  return null;
52548
52604
  }
52549
52605
  let nextIndex = lineBreakIndex + 1;
52550
- if (text[lineBreakIndex] === "\r" && text[nextIndex] === "\n") {
52606
+ if (text2[lineBreakIndex] === "\r" && text2[nextIndex] === "\n") {
52551
52607
  nextIndex += 1;
52552
52608
  }
52553
52609
  return {
52554
- line: text.slice(0, lineBreakIndex),
52555
- rest: text.slice(nextIndex)
52610
+ line: text2.slice(0, lineBreakIndex),
52611
+ rest: text2.slice(nextIndex)
52556
52612
  };
52557
52613
  }
52558
52614
  async function* iterateSseMessages(body, signal) {
@@ -52819,6 +52875,15 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
52819
52875
  type: "text",
52820
52876
  text: sanitizeSurrogates(item.text)
52821
52877
  };
52878
+ } else if (item.type === "video") {
52879
+ return {
52880
+ type: "video",
52881
+ source: {
52882
+ type: "base64",
52883
+ media_type: item.mimeType,
52884
+ data: item.data
52885
+ }
52886
+ };
52822
52887
  } else {
52823
52888
  return {
52824
52889
  type: "image",
@@ -52899,6 +52964,8 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
52899
52964
  toolResults.push({
52900
52965
  type: "tool_result",
52901
52966
  tool_use_id: msg.toolCallId,
52967
+ // MiniMax's Anthropic-compatible API accepts video in tool results;
52968
+ // the SDK's ToolResultBlockParam.content type predates video support.
52902
52969
  content: convertContentBlocks(msg.content),
52903
52970
  is_error: msg.isError
52904
52971
  });
@@ -52925,7 +52992,7 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
52925
52992
  if (lastMessage.role === "user") {
52926
52993
  if (Array.isArray(lastMessage.content)) {
52927
52994
  const lastBlock = lastMessage.content[lastMessage.content.length - 1];
52928
- if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "tool_result")) {
52995
+ if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "video" || lastBlock.type === "tool_result")) {
52929
52996
  lastBlock.cache_control = cacheControl;
52930
52997
  }
52931
52998
  } else if (typeof lastMessage.content === "string") {
@@ -54708,8 +54775,8 @@ var require_common = __commonJS({
54708
54775
  }
54709
54776
  function redactString(obj, key) {
54710
54777
  if (typeof obj === "object" && obj !== null && typeof obj[key] === "string") {
54711
- const text = obj[key];
54712
- if (/grant_type=/i.test(text) || /assertion=/i.test(text) || /secret/i.test(text)) {
54778
+ const text2 = obj[key];
54779
+ if (/grant_type=/i.test(text2) || /assertion=/i.test(text2) || /secret/i.test(text2)) {
54713
54780
  obj[key] = REDACT;
54714
54781
  }
54715
54782
  }
@@ -61537,8 +61604,8 @@ var init_body = __esm({
61537
61604
  * @return Promise
61538
61605
  */
61539
61606
  async json() {
61540
- const text = await this.text();
61541
- return JSON.parse(text);
61607
+ const text2 = await this.text();
61608
+ return JSON.parse(text2);
61542
61609
  }
61543
61610
  /**
61544
61611
  * Decode response as text
@@ -62690,7 +62757,7 @@ var require_gaxios = __commonJS({
62690
62757
  var retry_js_1 = require_retry3();
62691
62758
  var stream_1 = __require("stream");
62692
62759
  var interceptor_js_1 = require_interceptor();
62693
- var randomUUID16 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
62760
+ var randomUUID17 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
62694
62761
  var HTTP_STATUS_NO_CONTENT = 204;
62695
62762
  var Gaxios = class {
62696
62763
  agentCache = /* @__PURE__ */ new Map();
@@ -62963,7 +63030,7 @@ var require_gaxios = __commonJS({
62963
63030
  */
62964
63031
  ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
62965
63032
  if (opts.multipart?.length) {
62966
- const boundary = await randomUUID16();
63033
+ const boundary = await randomUUID17();
62967
63034
  preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
62968
63035
  opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
62969
63036
  } else if (shouldDirectlyPassData) {
@@ -64714,18 +64781,18 @@ var require_parse = __commonJS({
64714
64781
  n: "\n",
64715
64782
  r: "\r",
64716
64783
  t: " "
64717
- }, text, error = function(m2) {
64784
+ }, text2, error = function(m2) {
64718
64785
  throw {
64719
64786
  name: "SyntaxError",
64720
64787
  message: m2,
64721
64788
  at,
64722
- text
64789
+ text: text2
64723
64790
  };
64724
64791
  }, next = function(c) {
64725
64792
  if (c && c !== ch) {
64726
64793
  error("Expected '" + c + "' instead of '" + ch + "'");
64727
64794
  }
64728
- ch = text.charAt(at);
64795
+ ch = text2.charAt(at);
64729
64796
  at += 1;
64730
64797
  return ch;
64731
64798
  }, number44 = function() {
@@ -64772,12 +64839,12 @@ var require_parse = __commonJS({
64772
64839
  var startAt = at;
64773
64840
  while (next()) {
64774
64841
  if (ch === '"') {
64775
- if (at - 1 > startAt) string474 += text.substring(startAt, at - 1);
64842
+ if (at - 1 > startAt) string474 += text2.substring(startAt, at - 1);
64776
64843
  next();
64777
64844
  return string474;
64778
64845
  }
64779
64846
  if (ch === "\\") {
64780
- if (at - 1 > startAt) string474 += text.substring(startAt, at - 1);
64847
+ if (at - 1 > startAt) string474 += text2.substring(startAt, at - 1);
64781
64848
  next();
64782
64849
  if (ch === "u") {
64783
64850
  uffff = 0;
@@ -64910,7 +64977,7 @@ var require_parse = __commonJS({
64910
64977
  };
64911
64978
  return function(source, reviver) {
64912
64979
  var result;
64913
- text = source + "";
64980
+ text2 = source + "";
64914
64981
  at = 0;
64915
64982
  ch = " ";
64916
64983
  result = value();
@@ -65822,8 +65889,8 @@ var require_crypto = __commonJS({
65822
65889
  const result = new TextDecoder().decode(uint8array);
65823
65890
  return result;
65824
65891
  }
65825
- encodeBase64StringUtf8(text) {
65826
- const uint8array = new TextEncoder().encode(text);
65892
+ encodeBase64StringUtf8(text2) {
65893
+ const uint8array = new TextEncoder().encode(text2);
65827
65894
  const result = base64js.fromByteArray(uint8array);
65828
65895
  return result;
65829
65896
  }
@@ -65892,8 +65959,8 @@ var require_crypto2 = __commonJS({
65892
65959
  decodeBase64StringUtf8(base64) {
65893
65960
  return Buffer.from(base64, "base64").toString("utf-8");
65894
65961
  }
65895
- encodeBase64StringUtf8(text) {
65896
- return Buffer.from(text, "utf-8").toString("base64");
65962
+ encodeBase64StringUtf8(text2) {
65963
+ return Buffer.from(text2, "utf-8").toString("base64");
65897
65964
  }
65898
65965
  /**
65899
65966
  * Computes the SHA-256 hash of the provided string.
@@ -86338,8 +86405,8 @@ async function defaultParseResponse3(client, props) {
86338
86405
  const json2 = await response.json();
86339
86406
  return json2;
86340
86407
  }
86341
- const text = await response.text();
86342
- return text;
86408
+ const text2 = await response.text();
86409
+ return text2;
86343
86410
  })();
86344
86411
  loggerFor3(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails3({
86345
86412
  retryOfRequestLogID,
@@ -87916,7 +87983,7 @@ var init_node = __esm({
87916
87983
  if (this.candidates && this.candidates.length > 1) {
87917
87984
  console.warn("there are multiple candidates in the response, returning text from the first one.");
87918
87985
  }
87919
- let text = "";
87986
+ let text2 = "";
87920
87987
  let anyTextPartText = false;
87921
87988
  const nonTextParts = [];
87922
87989
  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 : []) {
@@ -87930,13 +87997,13 @@ var init_node = __esm({
87930
87997
  continue;
87931
87998
  }
87932
87999
  anyTextPartText = true;
87933
- text += part.text;
88000
+ text2 += part.text;
87934
88001
  }
87935
88002
  }
87936
88003
  if (nonTextParts.length > 0) {
87937
88004
  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.`);
87938
88005
  }
87939
- return anyTextPartText ? text : void 0;
88006
+ return anyTextPartText ? text2 : void 0;
87940
88007
  }
87941
88008
  /**
87942
88009
  * Returns the concatenation of all inline data parts from the first candidate
@@ -88189,7 +88256,7 @@ var init_node = __esm({
88189
88256
  */
88190
88257
  get text() {
88191
88258
  var _a5, _b, _c;
88192
- let text = "";
88259
+ let text2 = "";
88193
88260
  let anyTextPartFound = false;
88194
88261
  const nonTextParts = [];
88195
88262
  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 : []) {
@@ -88203,13 +88270,13 @@ var init_node = __esm({
88203
88270
  continue;
88204
88271
  }
88205
88272
  anyTextPartFound = true;
88206
- text += part.text;
88273
+ text2 += part.text;
88207
88274
  }
88208
88275
  }
88209
88276
  if (nonTextParts.length > 0) {
88210
88277
  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.`);
88211
88278
  }
88212
- return anyTextPartFound ? text : void 0;
88279
+ return anyTextPartFound ? text2 : void 0;
88213
88280
  }
88214
88281
  /**
88215
88282
  * Returns the concatenation of all inline data parts from the server content if present.
@@ -92881,9 +92948,9 @@ var init_node = __esm({
92881
92948
  }
92882
92949
  return n;
92883
92950
  };
92884
- safeJSON3 = (text) => {
92951
+ safeJSON3 = (text2) => {
92885
92952
  try {
92886
- return JSON.parse(text);
92953
+ return JSON.parse(text2);
92887
92954
  } catch (err) {
92888
92955
  return void 0;
92889
92956
  }
@@ -110746,8 +110813,8 @@ function findBoundary(buf) {
110746
110813
  return null;
110747
110814
  }
110748
110815
  function parseMessage2(chunk, parse2, state, dataRequired) {
110749
- const text = new TextDecoder().decode(chunk);
110750
- const lines = text.split(/\r\n|\r|\n/);
110816
+ const text2 = new TextDecoder().decode(chunk);
110817
+ const lines = text2.split(/\r\n|\r|\n/);
110751
110818
  const dataLines = [];
110752
110819
  const ret = {};
110753
110820
  let ignore = true;
@@ -133621,10 +133688,10 @@ function formatMistralError(error) {
133621
133688
  }
133622
133689
  return safeJsonStringify(error);
133623
133690
  }
133624
- function truncateErrorText(text, maxChars) {
133625
- if (text.length <= maxChars)
133626
- return text;
133627
- return `${text.slice(0, maxChars)}... [truncated ${text.length - maxChars} chars]`;
133691
+ function truncateErrorText(text2, maxChars) {
133692
+ if (text2.length <= maxChars)
133693
+ return text2;
133694
+ return `${text2.slice(0, maxChars)}... [truncated ${text2.length - maxChars} chars]`;
133628
133695
  }
133629
133696
  function safeJsonStringify(value) {
133630
133697
  try {
@@ -133744,7 +133811,7 @@ async function consumeChatStream(model, output, stream2, mistralStream) {
133744
133811
  continue;
133745
133812
  }
133746
133813
  if (item.type === "thinking") {
133747
- const deltaText = item.thinking.map((part) => "text" in part ? part.text : "").filter((text) => text.length > 0).join("");
133814
+ const deltaText = item.thinking.map((part) => "text" in part ? part.text : "").filter((text2) => text2.length > 0).join("");
133748
133815
  const thinkingDelta = sanitizeSurrogates(deltaText);
133749
133816
  if (!thinkingDelta)
133750
133817
  continue;
@@ -133941,8 +134008,8 @@ function toChatMessages(messages, supportsImages) {
133941
134008
  }
133942
134009
  return result;
133943
134010
  }
133944
- function buildToolResultText(text, hasImages, supportsImages, isError) {
133945
- const trimmed = text.trim();
134011
+ function buildToolResultText(text2, hasImages, supportsImages, isError) {
134012
+ const trimmed = text2.trim();
133946
134013
  const errorPrefix = isError ? "[tool error] " : "";
133947
134014
  if (trimmed.length > 0) {
133948
134015
  const imageSuffix = hasImages && !supportsImages ? "\n[tool image omitted: model does not support images]" : "";
@@ -134743,14 +134810,14 @@ async function* parseWebSocket(socket, signal, idleTimeoutMs) {
134743
134810
  };
134744
134811
  const onMessage = (event) => {
134745
134812
  void (async () => {
134746
- let text = null;
134813
+ let text2 = null;
134747
134814
  try {
134748
134815
  if (!event || typeof event !== "object" || !("data" in event))
134749
134816
  return;
134750
- text = await decodeWebSocketData(event.data);
134751
- if (!text)
134817
+ text2 = await decodeWebSocketData(event.data);
134818
+ if (!text2)
134752
134819
  return;
134753
- const parsed = JSON.parse(text);
134820
+ const parsed = JSON.parse(text2);
134754
134821
  const type = typeof parsed.type === "string" ? parsed.type : "";
134755
134822
  if (type === "response.completed" || type === "response.done" || type === "response.incomplete") {
134756
134823
  sawCompletion = true;
@@ -134761,7 +134828,7 @@ async function* parseWebSocket(socket, signal, idleTimeoutMs) {
134761
134828
  } catch (cause) {
134762
134829
  failed = new CodexProtocolError(`Invalid Codex WebSocket JSON: ${formatThrownValue(cause)}`, {
134763
134830
  cause,
134764
- payload: text
134831
+ payload: text2
134765
134832
  });
134766
134833
  done = true;
134767
134834
  wake();
@@ -142954,11 +143021,11 @@ function videoRequestConfig(input) {
142954
143021
  };
142955
143022
  }
142956
143023
  async function readMiniMaxJson(response) {
142957
- const text = await response.text();
143024
+ const text2 = await response.text();
142958
143025
  let body = {};
142959
- if (text) {
143026
+ if (text2) {
142960
143027
  try {
142961
- const parsed = JSON.parse(text);
143028
+ const parsed = JSON.parse(text2);
142962
143029
  if (isRecord2(parsed)) body = parsed;
142963
143030
  } catch {
142964
143031
  throw new Error("MiniMax video API returned invalid JSON");
@@ -143861,6 +143928,7 @@ __export(store_exports, {
143861
143928
  CodeGraphStore: () => CodeGraphStore
143862
143929
  });
143863
143930
  import { randomUUID as randomUUID6 } from "crypto";
143931
+ import { posix as pathPosix } from "path";
143864
143932
  function rowToFile(row) {
143865
143933
  return {
143866
143934
  id: row.id,
@@ -143911,6 +143979,26 @@ function rowToEdge(row) {
143911
143979
  ...row.sourceEpoch != null ? { sourceEpoch: Number(row.sourceEpoch) } : {}
143912
143980
  };
143913
143981
  }
143982
+ function resolveRelativeImportTarget(sourcePath, evidence, fileByPath) {
143983
+ const target = evidence?.trim().replace(/\\/g, "/");
143984
+ if (!target?.startsWith(".")) return void 0;
143985
+ const base = normalizeCodePath(pathPosix.normalize(pathPosix.join(pathPosix.dirname(sourcePath), target)));
143986
+ if (!base || base === ".." || base.startsWith("../")) return void 0;
143987
+ const candidates = [base];
143988
+ const extensionMatch = base.match(/(\.[A-Za-z0-9]+)$/);
143989
+ const hasExtension = Boolean(extensionMatch);
143990
+ if (!hasExtension) {
143991
+ const extensions = [...new Set([...fileByPath.keys()].map((path36) => path36.match(/(\.[A-Za-z0-9]+)$/)?.[1]).filter((extension3) => Boolean(extension3)))];
143992
+ for (const extension3 of extensions) {
143993
+ candidates.push(`${base}${extension3}`, `${base}/index${extension3}`);
143994
+ }
143995
+ } else {
143996
+ const sourceStem = base.slice(0, -extensionMatch[1].length);
143997
+ const sourceExtensions = extensionMatch[1] === ".js" ? [".ts", ".tsx", ".js", ".jsx"] : extensionMatch[1] === ".mjs" ? [".mts", ".mjs"] : extensionMatch[1] === ".cjs" ? [".cts", ".cjs"] : [];
143998
+ for (const extension3 of sourceExtensions) candidates.push(`${sourceStem}${extension3}`);
143999
+ }
144000
+ return candidates.map((candidate) => fileByPath.get(candidate)).find((file) => Boolean(file));
144001
+ }
143914
144002
  function rowToRef(row) {
143915
144003
  return {
143916
144004
  id: row.id,
@@ -143971,6 +144059,18 @@ function rowToSnapshot(row) {
143971
144059
  ...row.previousSnapshotId ? { previousSnapshotId: row.previousSnapshotId } : {}
143972
144060
  };
143973
144061
  }
144062
+ function rowToSnapshotFile(row) {
144063
+ return {
144064
+ snapshotId: row.snapshotId,
144065
+ projectId: row.projectId,
144066
+ fileId: row.fileId,
144067
+ path: row.path,
144068
+ contentHash: row.contentHash
144069
+ };
144070
+ }
144071
+ function snapshotIsIncomplete(snapshot) {
144072
+ return snapshot.completeness.skippedOversizedFiles > 0 || (snapshot.completeness.unreadableFiles ?? 0) > 0 || snapshot.completeness.removalScanDeferred;
144073
+ }
143974
144074
  var CodeGraphStore;
143975
144075
  var init_store = __esm({
143976
144076
  "src/codegraph/store.ts"() {
@@ -144142,6 +144242,7 @@ var init_store = __esm({
144142
144242
  }
144143
144243
  });
144144
144244
  tx();
144245
+ this.reconcileLocalImportTargets(projectId);
144145
144246
  }
144146
144247
  /**
144147
144248
  * Reconcile only files whose source changed plus files that disappeared.
@@ -144151,7 +144252,10 @@ var init_store = __esm({
144151
144252
  const changed = input.changed.filter((delta) => delta.file.projectId === projectId);
144152
144253
  const metadataOnly = (input.metadataOnly ?? []).filter((file) => file.projectId === projectId);
144153
144254
  const removedFileIds = input.removedFileIds ?? [];
144154
- if (changed.length === 0 && metadataOnly.length === 0 && removedFileIds.length === 0) return;
144255
+ if (changed.length === 0 && metadataOnly.length === 0 && removedFileIds.length === 0) {
144256
+ this.reconcileLocalImportTargets(projectId);
144257
+ return;
144258
+ }
144155
144259
  const staleRefsForFile = this.db.prepare(`
144156
144260
  UPDATE observation_code_refs
144157
144261
  SET status = 'stale', updatedAt = ?
@@ -144161,9 +144265,18 @@ var init_store = __esm({
144161
144265
  )
144162
144266
  )
144163
144267
  `);
144164
- const deleteEdgesForFile = this.db.prepare(`
144268
+ const deleteEdgesFromFile = this.db.prepare(`
144269
+ DELETE FROM code_edges
144270
+ WHERE projectId = ? AND fromFileId = ?
144271
+ `);
144272
+ const clearImportTargetsForFile = this.db.prepare(`
144273
+ UPDATE code_edges
144274
+ SET toFileId = NULL
144275
+ WHERE projectId = ? AND toFileId = ? AND type = 'imports'
144276
+ `);
144277
+ const deleteOtherIncomingEdgesForFile = this.db.prepare(`
144165
144278
  DELETE FROM code_edges
144166
- WHERE projectId = ? AND (fromFileId = ? OR toFileId = ?)
144279
+ WHERE projectId = ? AND toFileId = ? AND type != 'imports'
144167
144280
  `);
144168
144281
  const deleteSymbolsForFile = this.db.prepare(`DELETE FROM code_symbols WHERE projectId = ? AND fileId = ?`);
144169
144282
  const deleteFile = this.db.prepare(`DELETE FROM code_files WHERE projectId = ? AND id = ?`);
@@ -144200,14 +144313,18 @@ var init_store = __esm({
144200
144313
  const staleAt = (/* @__PURE__ */ new Date()).toISOString();
144201
144314
  for (const fileId of removedFileIds) {
144202
144315
  staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);
144203
- deleteEdgesForFile.run(projectId, fileId, fileId);
144316
+ deleteEdgesFromFile.run(projectId, fileId);
144317
+ clearImportTargetsForFile.run(projectId, fileId);
144318
+ deleteOtherIncomingEdgesForFile.run(projectId, fileId);
144204
144319
  deleteSymbolsForFile.run(projectId, fileId);
144205
144320
  deleteFile.run(projectId, fileId);
144206
144321
  }
144207
144322
  for (const delta of changed) {
144208
144323
  const fileId = delta.file.id;
144209
144324
  staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);
144210
- deleteEdgesForFile.run(projectId, fileId, fileId);
144325
+ deleteEdgesFromFile.run(projectId, fileId);
144326
+ clearImportTargetsForFile.run(projectId, fileId);
144327
+ deleteOtherIncomingEdgesForFile.run(projectId, fileId);
144211
144328
  deleteSymbolsForFile.run(projectId, fileId);
144212
144329
  writeFile8(delta.file);
144213
144330
  for (const symbol of delta.symbols) {
@@ -144245,6 +144362,7 @@ var init_store = __esm({
144245
144362
  for (const file of metadataOnly) writeFile8(file);
144246
144363
  });
144247
144364
  tx();
144365
+ this.reconcileLocalImportTargets(projectId);
144248
144366
  }
144249
144367
  upsertObservationRefs(refs) {
144250
144368
  if (refs.length === 0) return;
@@ -144306,6 +144424,25 @@ var init_store = __esm({
144306
144424
  });
144307
144425
  tx();
144308
144426
  }
144427
+ /**
144428
+ * Lite import extraction records the original import text first. Resolve only
144429
+ * local relative imports against the current index after each refresh, so an
144430
+ * added or removed target cannot leave a fabricated file-to-file relation.
144431
+ */
144432
+ reconcileLocalImportTargets(projectId) {
144433
+ const fileById = new Map(this.listFiles(projectId).map((file) => [file.id, file]));
144434
+ const fileByPath = new Map([...fileById.values()].map((file) => [file.path, file]));
144435
+ const update2 = this.db.prepare("UPDATE code_edges SET toFileId = ? WHERE id = ?");
144436
+ const tx = this.db.transaction(() => {
144437
+ for (const edge of this.listEdges(projectId)) {
144438
+ if (edge.type !== "imports" || !edge.fromFileId) continue;
144439
+ const source = fileById.get(edge.fromFileId);
144440
+ const target = source ? resolveRelativeImportTarget(source.path, edge.evidence, fileByPath) : void 0;
144441
+ update2.run(target?.id ?? null, edge.id);
144442
+ }
144443
+ });
144444
+ tx();
144445
+ }
144309
144446
  getFile(projectId, path36) {
144310
144447
  const row = this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? AND path = ?`).get(projectId, normalizeCodePath(path36));
144311
144448
  return row ? rowToFile(row) : null;
@@ -144380,6 +144517,18 @@ var init_store = __esm({
144380
144517
  ORDER BY observationId, status, id
144381
144518
  `).all(projectId).map(rowToRef);
144382
144519
  }
144520
+ /** Count distinct observations whose binding to these exact files is stale. */
144521
+ countStaleObservationRefsForFiles(projectId, fileIds) {
144522
+ const ids = [...new Set(fileIds.filter(Boolean))];
144523
+ if (ids.length === 0) return 0;
144524
+ const placeholders = ids.map(() => "?").join(", ");
144525
+ const row = this.db.prepare(`
144526
+ SELECT COUNT(DISTINCT observationId) AS count
144527
+ FROM observation_code_refs
144528
+ WHERE projectId = ? AND status = 'stale' AND fileId IN (${placeholders})
144529
+ `).get(projectId, ...ids);
144530
+ return Number(row?.count ?? 0);
144531
+ }
144383
144532
  listReferencedSymbols(projectId) {
144384
144533
  return this.db.prepare(`
144385
144534
  SELECT DISTINCT symbols.*
@@ -144401,6 +144550,94 @@ var init_store = __esm({
144401
144550
  "SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT ?"
144402
144551
  ).all(projectId, safeLimit2).map(rowToSnapshot);
144403
144552
  }
144553
+ listSnapshotFiles(snapshotId) {
144554
+ return this.db.prepare(`
144555
+ SELECT snapshotId, projectId, fileId, path, contentHash
144556
+ FROM code_state_snapshot_files
144557
+ WHERE snapshotId = ?
144558
+ ORDER BY path
144559
+ `).all(snapshotId).map(rowToSnapshotFile);
144560
+ }
144561
+ diffSnapshots(projectId, fromSnapshotId, toSnapshotId) {
144562
+ const snapshots = this.db.prepare(`
144563
+ SELECT * FROM code_state_snapshots WHERE id IN (?, ?)
144564
+ `).all(fromSnapshotId, toSnapshotId).map(rowToSnapshot);
144565
+ if (snapshots.length !== 2) {
144566
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "missing-snapshot", changes: [] };
144567
+ }
144568
+ if (snapshots.some((snapshot) => snapshot.projectId !== projectId)) {
144569
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "project-mismatch", changes: [] };
144570
+ }
144571
+ if (snapshots.some(snapshotIsIncomplete)) {
144572
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "incomplete-snapshot", changes: [] };
144573
+ }
144574
+ const before = this.listSnapshotFiles(fromSnapshotId);
144575
+ const after = this.listSnapshotFiles(toSnapshotId);
144576
+ if (before.length === 0 || after.length === 0) {
144577
+ return {
144578
+ projectId,
144579
+ fromSnapshotId,
144580
+ toSnapshotId,
144581
+ available: false,
144582
+ reason: "legacy-snapshot-without-manifest",
144583
+ changes: []
144584
+ };
144585
+ }
144586
+ const beforeByPath = new Map(before.map((file) => [file.path, file]));
144587
+ const afterByPath = new Map(after.map((file) => [file.path, file]));
144588
+ const paths = [.../* @__PURE__ */ new Set([...beforeByPath.keys(), ...afterByPath.keys()])].sort();
144589
+ const changes = [];
144590
+ for (const path36 of paths) {
144591
+ const oldFile = beforeByPath.get(path36);
144592
+ const newFile = afterByPath.get(path36);
144593
+ if (!oldFile && newFile) {
144594
+ changes.push({ path: path36, kind: "added", afterHash: newFile.contentHash });
144595
+ } else if (oldFile && !newFile) {
144596
+ changes.push({ path: path36, kind: "removed", beforeHash: oldFile.contentHash });
144597
+ } else if (oldFile && newFile && oldFile.contentHash !== newFile.contentHash) {
144598
+ changes.push({ path: path36, kind: "modified", beforeHash: oldFile.contentHash, afterHash: newFile.contentHash });
144599
+ }
144600
+ }
144601
+ return { projectId, fromSnapshotId, toSnapshotId, available: true, changes };
144602
+ }
144603
+ impactSlice(projectId, changedPaths, maxRelations = 24) {
144604
+ const safeLimit2 = Number.isFinite(maxRelations) ? Math.max(1, Math.min(100, Math.floor(maxRelations))) : 24;
144605
+ const normalizedPaths = [...new Set(changedPaths.map(normalizeCodePath).filter(Boolean))].sort();
144606
+ const files = this.listFiles(projectId);
144607
+ const fileById = new Map(files.map((file) => [file.id, file.path]));
144608
+ const fileIdBySymbolId = new Map(this.listSymbols(projectId).map((symbol) => [symbol.id, symbol.fileId]));
144609
+ const changedIds = new Set(files.filter((file) => normalizedPaths.includes(file.path)).map((file) => file.id));
144610
+ const direct = /* @__PURE__ */ new Set();
144611
+ let relationCount = 0;
144612
+ let truncated = false;
144613
+ for (const edge of this.listEdges(projectId)) {
144614
+ const endpoints = [
144615
+ edge.fromFileId,
144616
+ edge.toFileId,
144617
+ edge.fromSymbolId ? fileIdBySymbolId.get(edge.fromSymbolId) : void 0,
144618
+ edge.toSymbolId ? fileIdBySymbolId.get(edge.toSymbolId) : void 0
144619
+ ].filter((id) => Boolean(id));
144620
+ if (!endpoints.some((id) => changedIds.has(id))) continue;
144621
+ const relatedPaths = endpoints.filter((id) => !changedIds.has(id)).map((id) => fileById.get(id)).filter((path36) => Boolean(path36));
144622
+ if (relatedPaths.length === 0) continue;
144623
+ if (relationCount >= safeLimit2) {
144624
+ truncated = true;
144625
+ break;
144626
+ }
144627
+ relationCount += 1;
144628
+ for (const path36 of relatedPaths) direct.add(path36);
144629
+ }
144630
+ const snapshot = this.latestSnapshot(projectId);
144631
+ return {
144632
+ projectId,
144633
+ ...snapshot ? { snapshotId: snapshot.id } : {},
144634
+ changedPaths: normalizedPaths,
144635
+ directlyConnectedPaths: [...direct].sort(),
144636
+ relationCount,
144637
+ truncated,
144638
+ provider: snapshot?.provider ?? "lite"
144639
+ };
144640
+ }
144404
144641
  /**
144405
144642
  * Record a completed scan and mark all current structural facts with its
144406
144643
  * epoch. The snapshot is written only after refresh reconciliation succeeds,
@@ -144442,6 +144679,16 @@ var init_store = __esm({
144442
144679
  this.db.prepare(
144443
144680
  "UPDATE observation_code_refs SET snapshotId = ? WHERE projectId = ? AND status = 'current'"
144444
144681
  ).run(id, input.projectId);
144682
+ const snapshotFileRows = this.db.prepare(`
144683
+ SELECT id, projectId, path, contentHash FROM code_files WHERE projectId = ? ORDER BY path
144684
+ `).all(input.projectId);
144685
+ const insertSnapshotFile = this.db.prepare(`
144686
+ INSERT INTO code_state_snapshot_files (snapshotId, projectId, fileId, path, contentHash)
144687
+ VALUES (?, ?, ?, ?, ?)
144688
+ `);
144689
+ for (const file of snapshotFileRows) {
144690
+ insertSnapshotFile.run(id, file.projectId, file.id, file.path, file.contentHash);
144691
+ }
144445
144692
  snapshot = {
144446
144693
  ...input,
144447
144694
  id,
@@ -144607,8 +144854,8 @@ __export(lite_provider_exports, {
144607
144854
  import { createHash as createHash7 } from "crypto";
144608
144855
  import { readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
144609
144856
  import { join as join4, relative } from "path";
144610
- function hashText(text) {
144611
- return createHash7("sha256").update(text).digest("hex");
144857
+ function hashText(text2) {
144858
+ return createHash7("sha256").update(text2).digest("hex");
144612
144859
  }
144613
144860
  function extension2(path36) {
144614
144861
  const index = path36.lastIndexOf(".");
@@ -144652,19 +144899,19 @@ function walk(root, exclude, maxFiles) {
144652
144899
  visit(root);
144653
144900
  return out;
144654
144901
  }
144655
- function lineOf(text, index) {
144656
- return text.slice(0, index).split(/\r?\n/).length;
144902
+ function lineOf(text2, index) {
144903
+ return text2.slice(0, index).split(/\r?\n/).length;
144657
144904
  }
144658
- function extractSymbols(projectId, file, text, indexedAt) {
144905
+ function extractSymbols(projectId, file, text2, indexedAt) {
144659
144906
  const symbols = [];
144660
144907
  const profile = file.language ? languageProfiles[file.language] : void 0;
144661
144908
  const patterns = profile?.symbols ?? [];
144662
144909
  for (const { kind, re } of patterns) {
144663
144910
  re.lastIndex = 0;
144664
- for (const match2 of text.matchAll(re)) {
144911
+ for (const match2 of text2.matchAll(re)) {
144665
144912
  const name = match2[1];
144666
144913
  if (!name || name.includes("\n")) continue;
144667
- const startLine = lineOf(text, match2.index ?? 0);
144914
+ const startLine = lineOf(text2, match2.index ?? 0);
144668
144915
  const id = makeCodeSymbolId({ projectId, path: file.path, qualifiedName: name, kind });
144669
144916
  symbols.push({
144670
144917
  id,
@@ -144684,13 +144931,13 @@ function extractSymbols(projectId, file, text, indexedAt) {
144684
144931
  }
144685
144932
  return symbols;
144686
144933
  }
144687
- function extractImportEdges(projectId, file, text, indexedAt) {
144934
+ function extractImportEdges(projectId, file, text2, indexedAt) {
144688
144935
  const edges = [];
144689
144936
  const profile = file.language ? languageProfiles[file.language] : void 0;
144690
144937
  const imports = profile?.imports ?? [];
144691
144938
  for (const re of imports) {
144692
144939
  re.lastIndex = 0;
144693
- for (const match2 of text.matchAll(re)) {
144940
+ for (const match2 of text2.matchAll(re)) {
144694
144941
  const target = (match2[1] ?? "").trim();
144695
144942
  if (!target) continue;
144696
144943
  if (target.includes("\n")) {
@@ -144725,14 +144972,14 @@ function extractImportEdges(projectId, file, text, indexedAt) {
144725
144972
  function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
144726
144973
  const rel = normalizeCodePath(relative(projectRoot, abs));
144727
144974
  try {
144728
- const text = readFileSync6(abs, "utf-8");
144975
+ const text2 = readFileSync6(abs, "utf-8");
144729
144976
  const stat4 = fileStat ?? statSync3(abs);
144730
144977
  const file = {
144731
144978
  id: makeCodeFileId(projectId, rel),
144732
144979
  projectId,
144733
144980
  path: rel,
144734
144981
  language: languageForPath(rel),
144735
- contentHash: hashText(text),
144982
+ contentHash: hashText(text2),
144736
144983
  // Preserve filesystem precision. Rounding here made same-size edits in
144737
144984
  // a short Windows timestamp window indistinguishable to refresh.
144738
144985
  mtimeMs: Number(stat4.mtimeMs),
@@ -144742,8 +144989,8 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
144742
144989
  return {
144743
144990
  delta: {
144744
144991
  file,
144745
- symbols: extractSymbols(projectId, file, text, indexedAt),
144746
- edges: extractImportEdges(projectId, file, text, indexedAt)
144992
+ symbols: extractSymbols(projectId, file, text2, indexedAt),
144993
+ edges: extractImportEdges(projectId, file, text2, indexedAt)
144747
144994
  },
144748
144995
  unreadable: false
144749
144996
  };
@@ -145022,18 +145269,18 @@ __export(binder_exports, {
145022
145269
  function observationText(obs) {
145023
145270
  return [obs.title, obs.narrative, ...obs.facts ?? []].join("\n");
145024
145271
  }
145025
- function mentionsSymbol(text, symbol) {
145272
+ function mentionsSymbol(text2, symbol) {
145026
145273
  const name = symbol.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
145027
- return new RegExp(`(^|[^\\w$])${name}([^\\w$]|$)`).test(text);
145274
+ return new RegExp(`(^|[^\\w$])${name}([^\\w$]|$)`).test(text2);
145028
145275
  }
145029
- function identifierCandidates(text) {
145030
- return [...new Set(text.match(/[A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?/g) ?? [])];
145276
+ function identifierCandidates(text2) {
145277
+ return [...new Set(text2.match(/[A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?/g) ?? [])];
145031
145278
  }
145032
- function codeIdentifierCandidates(text) {
145279
+ function codeIdentifierCandidates(text2) {
145033
145280
  const explicit = /* @__PURE__ */ new Set();
145034
- for (const match2 of text.matchAll(/`([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)`/g)) explicit.add(match2[1]);
145035
- for (const match2 of text.matchAll(/\b([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)\s*\(/g)) explicit.add(match2[1]);
145036
- 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));
145281
+ for (const match2 of text2.matchAll(/`([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)`/g)) explicit.add(match2[1]);
145282
+ for (const match2 of text2.matchAll(/\b([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)\s*\(/g)) explicit.add(match2[1]);
145283
+ 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));
145037
145284
  }
145038
145285
  function fileRef(projectId, obs, file) {
145039
145286
  return {
@@ -145063,7 +145310,7 @@ function symbolRef(projectId, obs, file, symbol) {
145063
145310
  }
145064
145311
  function resolveObservationCodeRefs(obs, lookup2) {
145065
145312
  const refs = /* @__PURE__ */ new Map();
145066
- const text = observationText(obs);
145313
+ const text2 = observationText(obs);
145067
145314
  const candidateFiles = /* @__PURE__ */ new Map();
145068
145315
  for (const rawPath of obs.filesModified ?? []) {
145069
145316
  const file = lookup2.findFile(normalizeCodePath(rawPath));
@@ -145073,7 +145320,7 @@ function resolveObservationCodeRefs(obs, lookup2) {
145073
145320
  refs.set(ref.id, ref);
145074
145321
  }
145075
145322
  const hintedFileIds = new Set(candidateFiles.keys());
145076
- const symbolNames = hintedFileIds.size > 0 ? identifierCandidates(text) : codeIdentifierCandidates(text);
145323
+ const symbolNames = hintedFileIds.size > 0 ? identifierCandidates(text2) : codeIdentifierCandidates(text2);
145077
145324
  const symbols = lookup2.findSymbols(symbolNames, [...hintedFileIds]);
145078
145325
  const symbolsByName = /* @__PURE__ */ new Map();
145079
145326
  for (const symbol of symbols) {
@@ -145084,7 +145331,7 @@ function resolveObservationCodeRefs(obs, lookup2) {
145084
145331
  for (const group of symbolsByName.values()) {
145085
145332
  const candidates = group.length === 1 ? group : [];
145086
145333
  for (const symbol of candidates) {
145087
- if (!mentionsSymbol(text, symbol)) continue;
145334
+ if (!mentionsSymbol(text2, symbol)) continue;
145088
145335
  const file = candidateFiles.get(symbol.fileId) ?? lookup2.findFile(symbol.path);
145089
145336
  if (!file) continue;
145090
145337
  candidateFiles.set(file.id, file);
@@ -145812,8 +146059,8 @@ function taskTokens(task) {
145812
146059
  return normalizedTokens(task);
145813
146060
  }
145814
146061
  function scoreClaim(claim, tokens) {
145815
- const text = [claim.subject, claim.predicate, claim.objectValue].join(" ").toLocaleLowerCase("en-US");
145816
- const words = normalizedTokens(text);
146062
+ const text2 = [claim.subject, claim.predicate, claim.objectValue].join(" ").toLocaleLowerCase("en-US");
146063
+ const words = normalizedTokens(text2);
145817
146064
  let matches = 0;
145818
146065
  for (const token of tokens) {
145819
146066
  if (words.has(token)) matches += 1;
@@ -146713,6 +146960,128 @@ var init_workflow_store = __esm({
146713
146960
  }
146714
146961
  });
146715
146962
 
146963
+ // src/knowledge/outcome-types.ts
146964
+ function qualityFromOutcome(signal) {
146965
+ if (!signal) return void 0;
146966
+ if (signal.kind === "verification-failed" || signal.kind === "user-correction" || signal.kind === "source-changed" || signal.kind === "conflict-confirmed") {
146967
+ return "degraded";
146968
+ }
146969
+ if (signal.kind === "verification-passed" || signal.kind === "verified-reuse" || signal.kind === "user-pin") {
146970
+ return "verified";
146971
+ }
146972
+ return void 0;
146973
+ }
146974
+ var MEMORY_OUTCOME_CANDIDATE_KINDS, MEMORY_OUTCOME_SIGNAL_KINDS;
146975
+ var init_outcome_types = __esm({
146976
+ "src/knowledge/outcome-types.ts"() {
146977
+ "use strict";
146978
+ init_esm_shims();
146979
+ MEMORY_OUTCOME_CANDIDATE_KINDS = ["claim", "durable-memory", "workflow"];
146980
+ MEMORY_OUTCOME_SIGNAL_KINDS = [
146981
+ "verification-passed",
146982
+ "verification-failed",
146983
+ "verified-reuse",
146984
+ "user-pin",
146985
+ "user-correction",
146986
+ "source-changed",
146987
+ "conflict-confirmed",
146988
+ "manual-review"
146989
+ ];
146990
+ }
146991
+ });
146992
+
146993
+ // src/knowledge/outcome-store.ts
146994
+ import { randomUUID as randomUUID10 } from "crypto";
146995
+ function optionalText4(value) {
146996
+ return typeof value === "string" && value.trim() ? value : void 0;
146997
+ }
146998
+ function text(value, field, max = 1e3) {
146999
+ const safe = sanitizeCredentials(value).replace(/\s+/g, " ").trim();
147000
+ if (!safe) throw new Error("Outcome signal " + field + " is required.");
147001
+ if (safe.length > max) throw new Error("Outcome signal " + field + " is too long.");
147002
+ return safe;
147003
+ }
147004
+ function oneOf(value, values, field) {
147005
+ if (typeof value !== "string" || !values.includes(value)) {
147006
+ throw new Error("Outcome signal " + field + " is invalid.");
147007
+ }
147008
+ return value;
147009
+ }
147010
+ function rowToSignal(row) {
147011
+ return {
147012
+ id: row.id,
147013
+ projectId: row.projectId,
147014
+ candidateKind: row.candidateKind,
147015
+ candidateId: row.candidateId,
147016
+ kind: row.kind,
147017
+ sourceRef: row.sourceRef,
147018
+ ...optionalText4(row.snapshotId) ? { snapshotId: row.snapshotId } : {},
147019
+ ...optionalText4(row.detail) ? { detail: row.detail } : {},
147020
+ observedAt: row.observedAt
147021
+ };
147022
+ }
147023
+ var OutcomeStore;
147024
+ var init_outcome_store = __esm({
147025
+ "src/knowledge/outcome-store.ts"() {
147026
+ "use strict";
147027
+ init_esm_shims();
147028
+ init_secret_filter();
147029
+ init_sqlite_db();
147030
+ init_outcome_types();
147031
+ OutcomeStore = class {
147032
+ db = null;
147033
+ async init(dataDir) {
147034
+ this.db = getDatabase(dataDir);
147035
+ }
147036
+ record(input) {
147037
+ const signal = {
147038
+ id: randomUUID10(),
147039
+ projectId: text(input.projectId, "project id"),
147040
+ candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
147041
+ candidateId: text(input.candidateId, "candidate id"),
147042
+ kind: oneOf(input.kind, MEMORY_OUTCOME_SIGNAL_KINDS, "kind"),
147043
+ sourceRef: text(input.sourceRef, "source reference"),
147044
+ ...input.snapshotId ? { snapshotId: text(input.snapshotId, "snapshot id") } : {},
147045
+ ...input.detail ? { detail: text(input.detail, "detail") } : {},
147046
+ observedAt: input.observedAt ?? (/* @__PURE__ */ new Date()).toISOString()
147047
+ };
147048
+ this.db.prepare(`
147049
+ INSERT INTO memory_outcome_signals (
147050
+ id, projectId, candidateKind, candidateId, kind, sourceRef, snapshotId, detail, observedAt
147051
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
147052
+ `).run(
147053
+ signal.id,
147054
+ signal.projectId,
147055
+ signal.candidateKind,
147056
+ signal.candidateId,
147057
+ signal.kind,
147058
+ signal.sourceRef,
147059
+ signal.snapshotId ?? null,
147060
+ signal.detail ?? null,
147061
+ signal.observedAt
147062
+ );
147063
+ return signal;
147064
+ }
147065
+ latestForCandidates(projectId, candidateKind, candidateIds) {
147066
+ const ids = [...new Set(candidateIds.filter(Boolean))];
147067
+ if (ids.length === 0) return /* @__PURE__ */ new Map();
147068
+ const placeholders = ids.map(() => "?").join(", ");
147069
+ const rows = this.db.prepare(`
147070
+ SELECT * FROM memory_outcome_signals
147071
+ WHERE projectId = ? AND candidateKind = ? AND candidateId IN (${placeholders})
147072
+ ORDER BY observedAt DESC, id DESC
147073
+ `).all(projectId, candidateKind, ...ids);
147074
+ const latest = /* @__PURE__ */ new Map();
147075
+ for (const row of rows) {
147076
+ const signal = rowToSignal(row);
147077
+ if (!latest.has(signal.candidateId)) latest.set(signal.candidateId, signal);
147078
+ }
147079
+ return latest;
147080
+ }
147081
+ };
147082
+ }
147083
+ });
147084
+
146716
147085
  // src/codegraph/task-lens.ts
146717
147086
  var task_lens_exports = {};
146718
147087
  __export(task_lens_exports, {
@@ -146729,31 +147098,31 @@ __export(task_lens_exports, {
146729
147098
  function normalizePath2(path36) {
146730
147099
  return path36.replace(/\\/g, "/");
146731
147100
  }
146732
- function tokenize3(text) {
146733
- return (text.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
147101
+ function tokenize3(text2) {
147102
+ return (text2.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
146734
147103
  }
146735
- function containsTaskKeyword(text, keyword) {
147104
+ function containsTaskKeyword(text2, keyword) {
146736
147105
  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");
146737
147106
  let match2;
146738
- while ((match2 = matcher.exec(text)) !== null) {
147107
+ while ((match2 = matcher.exec(text2)) !== null) {
146739
147108
  const keywordIndex = match2.index + (match2[1]?.length ?? 0);
146740
- if (!isNegatedTaskKeyword(text, keywordIndex)) return true;
147109
+ if (!isNegatedTaskKeyword(text2, keywordIndex)) return true;
146741
147110
  }
146742
147111
  return false;
146743
147112
  }
146744
- function isNegatedTaskKeyword(text, keywordIndex) {
147113
+ function isNegatedTaskKeyword(text2, keywordIndex) {
146745
147114
  const boundary = Math.max(
146746
- text.lastIndexOf(".", keywordIndex - 1),
146747
- text.lastIndexOf("!", keywordIndex - 1),
146748
- text.lastIndexOf("?", keywordIndex - 1),
146749
- text.lastIndexOf(";", keywordIndex - 1),
146750
- text.lastIndexOf("\n", keywordIndex - 1),
146751
- text.lastIndexOf("\u3002", keywordIndex - 1),
146752
- text.lastIndexOf("\uFF01", keywordIndex - 1),
146753
- text.lastIndexOf("\uFF1F", keywordIndex - 1),
146754
- text.lastIndexOf("\uFF1B", keywordIndex - 1)
147115
+ text2.lastIndexOf(".", keywordIndex - 1),
147116
+ text2.lastIndexOf("!", keywordIndex - 1),
147117
+ text2.lastIndexOf("?", keywordIndex - 1),
147118
+ text2.lastIndexOf(";", keywordIndex - 1),
147119
+ text2.lastIndexOf("\n", keywordIndex - 1),
147120
+ text2.lastIndexOf("\u3002", keywordIndex - 1),
147121
+ text2.lastIndexOf("\uFF01", keywordIndex - 1),
147122
+ text2.lastIndexOf("\uFF1F", keywordIndex - 1),
147123
+ text2.lastIndexOf("\uFF1B", keywordIndex - 1)
146755
147124
  );
146756
- let prefix = text.slice(boundary + 1, keywordIndex).toLowerCase();
147125
+ let prefix = text2.slice(boundary + 1, keywordIndex).toLowerCase();
146757
147126
  const contrast = /(?:,|\uff0c)\s*(?:but|however|instead|yet|\u4f46\u662f|\u4f46|\u800c\u662f)\s*/gi;
146758
147127
  let contrastMatch;
146759
147128
  let contrastEnd = -1;
@@ -146776,9 +147145,9 @@ function resolveTaskLens(task) {
146776
147145
  };
146777
147146
  for (const id of LENS_PRIORITY) {
146778
147147
  const score = KEYWORDS[id].reduce((sum, keyword) => sum + (containsTaskKeyword(normalized, keyword) ? 1 : 0), 0);
146779
- const priority = LENS_PRIORITY.indexOf(id);
146780
- if (score > best.score || score === best.score && score > 0 && priority < best.priority) {
146781
- best = { id, score, priority };
147148
+ const priority2 = LENS_PRIORITY.indexOf(id);
147149
+ if (score > best.score || score === best.score && score > 0 && priority2 < best.priority) {
147150
+ best = { id, score, priority: priority2 };
146782
147151
  }
146783
147152
  }
146784
147153
  return best.score > 0 ? LENSES[best.id] : LENSES.general;
@@ -146820,20 +147189,20 @@ function pathKindScore(path36, lens) {
146820
147189
  return 0;
146821
147190
  }
146822
147191
  }
146823
- function tokenScore(text, tokens) {
147192
+ function tokenScore(text2, tokens) {
146824
147193
  if (tokens.length === 0) return 0;
146825
- const normalized = text.toLowerCase();
147194
+ const normalized = text2.toLowerCase();
146826
147195
  return tokens.reduce((sum, token) => sum + (normalized.includes(token) ? 12 : 0), 0);
146827
147196
  }
146828
147197
  function sourceTaskMatchScore(source, task) {
146829
147198
  const tokens = tokenize3(task ?? "");
146830
147199
  if (tokens.length === 0) return 0;
146831
- const text = [
147200
+ const text2 = [
146832
147201
  source.title,
146833
147202
  source.path ?? "",
146834
147203
  source.symbol ?? ""
146835
147204
  ].join("\n").toLowerCase();
146836
- const matches = tokens.filter((token) => text.includes(token)).length;
147205
+ const matches = tokens.filter((token) => text2.includes(token)).length;
146837
147206
  if (matches >= 2) return 40;
146838
147207
  if (matches === 1) return 24;
146839
147208
  return 0;
@@ -146872,8 +147241,8 @@ function lensPathCandidates(lens) {
146872
147241
  }
146873
147242
  function scoreLensSource(source, lens, task) {
146874
147243
  const tokens = tokenize3(task ?? "");
146875
- const text = [source.title, source.type, source.path ?? "", source.symbol ?? ""].join("\n");
146876
- return pathKindScore(source.path ?? "", lens) + tokenScore(text, tokens) + sourceTaskMatchScore(source, task);
147244
+ const text2 = [source.title, source.type, source.path ?? "", source.symbol ?? ""].join("\n");
147245
+ return pathKindScore(source.path ?? "", lens) + tokenScore(text2, tokens) + sourceTaskMatchScore(source, task);
146877
147246
  }
146878
147247
  function rankLensSources(sources, lens, task) {
146879
147248
  return [...sources].map((source, index) => ({
@@ -147116,7 +147485,7 @@ function requiredText(data, key) {
147116
147485
  }
147117
147486
  return value.trim();
147118
147487
  }
147119
- function optionalText4(data, key) {
147488
+ function optionalText5(data, key) {
147120
147489
  const value = data[key];
147121
147490
  if (value === void 0 || value === null || value === "") return void 0;
147122
147491
  if (typeof value !== "string") throw new Error("workflow frontmatter field " + key + " must be text");
@@ -147159,11 +147528,11 @@ function phaseFromValue(value, index) {
147159
147528
  }
147160
147529
  const data = value;
147161
147530
  const title = requiredText(data, "title");
147162
- const phaseId = optionalText4(data, "id") ?? slug(title) + "-" + (index + 1);
147531
+ const phaseId = optionalText5(data, "id") ?? slug(title) + "-" + (index + 1);
147163
147532
  return {
147164
147533
  id: phaseId,
147165
147534
  title,
147166
- instructions: optionalText4(data, "instructions") ?? "",
147535
+ instructions: optionalText5(data, "instructions") ?? "",
147167
147536
  branches: optionalStringArray(data, "branches"),
147168
147537
  expectedOutputs: optionalStringArray(data, "expectedOutputs"),
147169
147538
  verificationGates: optionalStringArray(data, "verificationGates")
@@ -147272,7 +147641,7 @@ function parsedWorkflow(data, body, input) {
147272
147641
  id: requiredText(data, "id"),
147273
147642
  workspaceId: input.workspaceId,
147274
147643
  title: requiredText(data, "title"),
147275
- description: optionalText4(data, "description") ?? "",
147644
+ description: optionalText5(data, "description") ?? "",
147276
147645
  status: optionalStatus(data),
147277
147646
  version: optionalNumber(data, "version", 1),
147278
147647
  taskLenses: optionalStringArray(data, "taskLenses"),
@@ -147291,9 +147660,9 @@ function parsedWorkflow(data, body, input) {
147291
147660
  sourcePath: normalizeSourcePath(input.sourcePath),
147292
147661
  sourceHash: "",
147293
147662
  contentHash: input.contentHash,
147294
- createdAt: optionalText4(data, "createdAt") ?? now2(),
147295
- updatedAt: optionalText4(data, "updatedAt") ?? now2(),
147296
- ...optionalText4(data, "importedFrom") ? { importedFrom: optionalText4(data, "importedFrom") } : {}
147663
+ createdAt: optionalText5(data, "createdAt") ?? now2(),
147664
+ updatedAt: optionalText5(data, "updatedAt") ?? now2(),
147665
+ ...optionalText5(data, "importedFrom") ? { importedFrom: optionalText5(data, "importedFrom") } : {}
147297
147666
  };
147298
147667
  if (candidate.phases.length === 0) {
147299
147668
  throw new Error("workflow must contain at least one phase or a non-empty body");
@@ -147392,11 +147761,11 @@ async function syncCanonicalWorkflows(workspace) {
147392
147761
  return { workflows, errors };
147393
147762
  }
147394
147763
  function inferTaskLenses(value) {
147395
- const text = value.toLowerCase();
147396
- return Object.entries(LENS_TERMS).filter(([, terms]) => terms.some((term) => text.includes(term))).map(([lens]) => lens);
147764
+ const text2 = value.toLowerCase();
147765
+ return Object.entries(LENS_TERMS).filter(([, terms]) => terms.some((term) => text2.includes(term))).map(([lens]) => lens);
147397
147766
  }
147398
147767
  function taskScore(workflow, task) {
147399
- const text = task.toLowerCase();
147768
+ const text2 = task.toLowerCase();
147400
147769
  let score = 0;
147401
147770
  const reasons = [];
147402
147771
  const matchedLenses = /* @__PURE__ */ new Set();
@@ -147663,7 +148032,31 @@ async function recordWorkflowRun(input) {
147663
148032
  throw new Error("Workflow was not found for this workspace");
147664
148033
  }
147665
148034
  if (!input.run.task.trim()) throw new Error("Workflow run task is required");
147666
- return store.recordRun(input.run);
148035
+ const run = store.recordRun(input.run);
148036
+ const kind = run.outcome === "passed" && run.verificationVerdict === "passed" ? "verification-passed" : run.outcome === "failed" || run.verificationVerdict === "failed" ? "verification-failed" : void 0;
148037
+ if (!kind) return run;
148038
+ const evidence = /* @__PURE__ */ new Map();
148039
+ evidence.set(workflow.id, "workflow");
148040
+ for (const reference of run.selectedEvidence) {
148041
+ const match2 = /^(claim|durable):(.+)$/.exec(reference);
148042
+ if (!match2) continue;
148043
+ evidence.set(match2[2], match2[1] === "claim" ? "claim" : "durable-memory");
148044
+ }
148045
+ const outcomes = new OutcomeStore();
148046
+ await outcomes.init(workflowStoreDataDir(input.workspace));
148047
+ for (const [candidateId, candidateKind] of evidence) {
148048
+ outcomes.record({
148049
+ projectId: run.projectId,
148050
+ candidateKind,
148051
+ candidateId,
148052
+ kind,
148053
+ sourceRef: "workflow-run:" + run.id,
148054
+ ...run.startingSnapshotId ? { snapshotId: run.startingSnapshotId } : {},
148055
+ ...run.failureReason ? { detail: run.failureReason } : {},
148056
+ observedAt: run.completedAt ?? run.startedAt
148057
+ });
148058
+ }
148059
+ return run;
147667
148060
  }
147668
148061
  async function selectWorkspaceWorkflows(input) {
147669
148062
  const synced = await syncCanonicalWorkflows(input.workspace);
@@ -147688,6 +148081,7 @@ var init_workflows2 = __esm({
147688
148081
  init_workflow_sync();
147689
148082
  init_workspace();
147690
148083
  init_workflow_store();
148084
+ init_outcome_store();
147691
148085
  init_task_lens();
147692
148086
  KNOWN_AGENTS = [
147693
148087
  "windsurf",
@@ -150711,7 +151105,7 @@ function evidenceScore2(obs) {
150711
151105
  }
150712
151106
  function scoreForPacket(obs, queryTokens, referenceTime, broadMemoryQuery) {
150713
151107
  let score = 0;
150714
- const text = normalizeText3([
151108
+ const text2 = normalizeText3([
150715
151109
  obs.title,
150716
151110
  obs.narrative,
150717
151111
  obs.entityName,
@@ -150720,15 +151114,15 @@ function scoreForPacket(obs, queryTokens, referenceTime, broadMemoryQuery) {
150720
151114
  ...obs.relatedEntities ?? [],
150721
151115
  ...obs.relatedCommits ?? []
150722
151116
  ].join(" "));
150723
- const matchingTokens = queryTokens.filter((token) => text.includes(token));
151117
+ const matchingTokens = queryTokens.filter((token) => text2.includes(token));
150724
151118
  score += matchingTokens.length * 4;
150725
151119
  if (queryTokens.length > 0 && matchingTokens.length === 0) {
150726
151120
  score -= 8;
150727
151121
  }
150728
- if (broadMemoryQuery && /memorix|memcode|memory-(?:graph|injection|runtime|quality|formation)|graph-context/.test(text)) {
151122
+ if (broadMemoryQuery && /memorix|memcode|memory-(?:graph|injection|runtime|quality|formation)|graph-context/.test(text2)) {
150729
151123
  score += 8;
150730
151124
  }
150731
- if (/\bmemory[- ]?game\b|e2e-test\/memory-game|team-handoff/.test(text)) {
151125
+ if (/\bmemory[- ]?game\b|e2e-test\/memory-game|team-handoff/.test(text2)) {
150732
151126
  score -= broadMemoryQuery ? 12 : 4;
150733
151127
  }
150734
151128
  score += obs.valueCategory === "core" ? 6 : 0;
@@ -153458,8 +153852,8 @@ async function extractFactsWithLLM(narrative, title, existingFacts) {
153458
153852
  Content: ${narrative}${existingFacts.length > 0 ? `
153459
153853
  Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
153460
153854
  const response = await callLLM2(LLM_EXTRACT_PROMPT, input);
153461
- const text = response.content.trim();
153462
- const jsonMatch = text.match(/\{[\s\S]*\}/);
153855
+ const text2 = response.content.trim();
153856
+ const jsonMatch = text2.match(/\{[\s\S]*\}/);
153463
153857
  if (!jsonMatch) return [];
153464
153858
  const parsed = JSON.parse(jsonMatch[0]);
153465
153859
  const facts = parsed.facts;
@@ -153712,8 +154106,8 @@ Facts: ${extracted.facts.join("; ")}
153712
154106
  EXISTING MEMORIES:
153713
154107
  ${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Facts: ${m2.facts}`).join("\n")}`;
153714
154108
  const response = await callLLM2(LLM_RESOLVE_PROMPT, input);
153715
- const text = response.content.trim();
153716
- const jsonMatch = text.match(/\{[\s\S]*\}/);
154109
+ const text2 = response.content.trim();
154110
+ const jsonMatch = text2.match(/\{[\s\S]*\}/);
153717
154111
  if (!jsonMatch) return null;
153718
154112
  const parsed = JSON.parse(jsonMatch[0]);
153719
154113
  const action = parsed.action?.toUpperCase();
@@ -154590,8 +154984,8 @@ function isNoiseObservation(obs) {
154590
154984
  return NOISE_PATTERNS2.some((pattern) => pattern.test(title)) || isCommandTrace(obs);
154591
154985
  }
154592
154986
  function isSystemSelfObservation(obs) {
154593
- const text = stringifyObservation(obs, false);
154594
- return SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(text));
154987
+ const text2 = stringifyObservation(obs, false);
154988
+ return SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(text2));
154595
154989
  }
154596
154990
  function readerForAlias(reader, aliases, observation) {
154597
154991
  if (!reader) return void 0;
@@ -154614,8 +155008,8 @@ function continuationTaskTokens(task) {
154614
155008
  function continuationScore(observation, projectTokens, task) {
154615
155009
  let score = scoreObservationForSessionContext(observation, projectTokens);
154616
155010
  if (observation.type === "session-request" || observation.type === "what-changed") score += 1;
154617
- const text = stringifyObservation(observation);
154618
- const matches = continuationTaskTokens(task).filter((token) => text.includes(token)).length;
155011
+ const text2 = stringifyObservation(observation);
155012
+ const matches = continuationTaskTokens(task).filter((token) => text2.includes(token)).length;
154619
155013
  score += Math.min(matches, 2) * 2;
154620
155014
  return score;
154621
155015
  }
@@ -154649,8 +155043,8 @@ async function getSessionResumeBrief(projectId, task, reader) {
154649
155043
  memories
154650
155044
  };
154651
155045
  }
154652
- function compactResumeText(text, limit2) {
154653
- const normalized = text.replace(/\s+/g, " ").trim();
155046
+ function compactResumeText(text2, limit2) {
155047
+ const normalized = text2.replace(/\s+/g, " ").trim();
154654
155048
  return normalized.length <= limit2 ? normalized : `${normalized.slice(0, Math.max(0, limit2 - 3)).trimEnd()}...`;
154655
155049
  }
154656
155050
  function renderSessionResumeCard(brief) {
@@ -154672,11 +155066,11 @@ function renderSessionResumeCard(brief) {
154672
155066
  }
154673
155067
  function scoreObservationForSessionContext(obs, projectTokens, now3 = Date.now()) {
154674
155068
  let score = TYPE_WEIGHTS2[obs.type] ?? 1;
154675
- const text = stringifyObservation(obs);
155069
+ const text2 = stringifyObservation(obs);
154676
155070
  const ageDays = Math.max(0, (now3 - new Date(obs.createdAt).getTime()) / (1e3 * 60 * 60 * 24));
154677
155071
  score += Math.max(0.2, 2.5 - Math.min(ageDays, 45) * 0.05);
154678
155072
  if (projectTokens.length > 0) {
154679
- const matchingTokens = projectTokens.filter((token) => text.includes(token));
155073
+ const matchingTokens = projectTokens.filter((token) => text2.includes(token));
154680
155074
  if (matchingTokens.length > 0) {
154681
155075
  score += 2 + matchingTokens.length * 0.6;
154682
155076
  } else if ((obs.filesModified?.length ?? 0) > 0) {
@@ -154992,7 +155386,7 @@ var owner_exports = {};
154992
155386
  __export(owner_exports, {
154993
155387
  resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
154994
155388
  });
154995
- import { randomUUID as randomUUID10 } from "crypto";
155389
+ import { randomUUID as randomUUID11 } from "crypto";
154996
155390
  import { promises as fs17 } from "fs";
154997
155391
  import path25 from "path";
154998
155392
  function ownerPath(dataDir) {
@@ -155022,7 +155416,7 @@ async function resolveLocalMemoryOwner(dataDir, options = {}) {
155022
155416
  await fs17.mkdir(path25.dirname(filePath), { recursive: true });
155023
155417
  const created = {
155024
155418
  version: 1,
155025
- id: "local-" + randomUUID10(),
155419
+ id: "local-" + randomUUID11(),
155026
155420
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
155027
155421
  };
155028
155422
  try {
@@ -155045,8 +155439,8 @@ var init_owner = __esm({
155045
155439
  });
155046
155440
 
155047
155441
  // src/memory/long-term-store.ts
155048
- import { randomUUID as randomUUID11 } from "crypto";
155049
- function optionalText5(value) {
155442
+ import { randomUUID as randomUUID12 } from "crypto";
155443
+ function optionalText6(value) {
155050
155444
  return typeof value === "string" && value.trim() ? value : void 0;
155051
155445
  }
155052
155446
  function arrayValue2(value) {
@@ -155071,17 +155465,17 @@ function rowToMemory(row) {
155071
155465
  content: row.content,
155072
155466
  facts: arrayValue2(row.factsJson),
155073
155467
  tags: arrayValue2(row.tagsJson),
155074
- ...optionalText5(row.applicability) ? { applicability: row.applicability } : {},
155468
+ ...optionalText6(row.applicability) ? { applicability: row.applicability } : {},
155075
155469
  origin: row.origin,
155076
155470
  createdAt: row.createdAt,
155077
155471
  updatedAt: row.updatedAt,
155078
- ...optionalText5(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
155079
- ...optionalText5(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
155080
- ...optionalText5(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
155081
- ...optionalText5(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
155082
- ...optionalText5(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
155472
+ ...optionalText6(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
155473
+ ...optionalText6(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
155474
+ ...optionalText6(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
155475
+ ...optionalText6(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
155476
+ ...optionalText6(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
155083
155477
  accessCount: Number(row.accessCount ?? 0),
155084
- ...optionalText5(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
155478
+ ...optionalText6(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
155085
155479
  };
155086
155480
  }
155087
155481
  function rowToEvidence2(row) {
@@ -155091,8 +155485,8 @@ function rowToEvidence2(row) {
155091
155485
  kind: row.kind,
155092
155486
  referenceId: row.referenceId,
155093
155487
  relation: row.relation,
155094
- ...optionalText5(row.locator) ? { locator: row.locator } : {},
155095
- ...optionalText5(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
155488
+ ...optionalText6(row.locator) ? { locator: row.locator } : {},
155489
+ ...optionalText6(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
155096
155490
  createdAt: row.createdAt
155097
155491
  };
155098
155492
  }
@@ -155101,9 +155495,9 @@ function rowToEvent2(row) {
155101
155495
  id: row.id,
155102
155496
  memoryId: row.memoryId,
155103
155497
  kind: row.kind,
155104
- ...optionalText5(row.fromState) ? { fromState: row.fromState } : {},
155105
- ...optionalText5(row.toState) ? { toState: row.toState } : {},
155106
- ...optionalText5(row.detail) ? { detail: row.detail } : {},
155498
+ ...optionalText6(row.fromState) ? { fromState: row.fromState } : {},
155499
+ ...optionalText6(row.toState) ? { toState: row.toState } : {},
155500
+ ...optionalText6(row.detail) ? { detail: row.detail } : {},
155107
155501
  createdAt: row.createdAt
155108
155502
  };
155109
155503
  }
@@ -155205,7 +155599,7 @@ var init_long_term_store = __esm({
155205
155599
  }
155206
155600
  insertEvidence(input) {
155207
155601
  const evidence = {
155208
- id: randomUUID11(),
155602
+ id: randomUUID12(),
155209
155603
  ...input,
155210
155604
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
155211
155605
  };
@@ -155232,7 +155626,7 @@ var init_long_term_store = __esm({
155232
155626
  }
155233
155627
  recordEvent(input) {
155234
155628
  const event = {
155235
- id: randomUUID11(),
155629
+ id: randomUUID12(),
155236
155630
  ...input,
155237
155631
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
155238
155632
  };
@@ -155320,7 +155714,7 @@ __export(long_term_exports, {
155320
155714
  selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
155321
155715
  supersedeLongTermMemory: () => supersedeLongTermMemory
155322
155716
  });
155323
- import { randomUUID as randomUUID12 } from "crypto";
155717
+ import { randomUUID as randomUUID13 } from "crypto";
155324
155718
  function isOneOf(value, values) {
155325
155719
  return typeof value === "string" && values.includes(value);
155326
155720
  }
@@ -155502,7 +155896,7 @@ async function createManualLongTermMemory(input) {
155502
155896
  const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
155503
155897
  if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
155504
155898
  assertScope(input.scope);
155505
- const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID12(), relation: "supports" }];
155899
+ const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID13(), relation: "supports" }];
155506
155900
  return createLongTermMemoryWithDataDir({
155507
155901
  dataDir: input.dataDir,
155508
155902
  originProjectId: input.projectId,
@@ -155557,7 +155951,7 @@ async function createLongTermMemoryWithDataDir(input) {
155557
155951
  assertPortableEvidence(input.scope, portability, evidenceInputs);
155558
155952
  const now3 = (/* @__PURE__ */ new Date()).toISOString();
155559
155953
  const memory = {
155560
- id: randomUUID12(),
155954
+ id: randomUUID13(),
155561
155955
  originProjectId: compactText2(input.originProjectId, "origin project id", 1e3),
155562
155956
  ownerId: compactText2(input.ownerId, "owner id", 160),
155563
155957
  scope: input.scope,
@@ -155808,12 +156202,99 @@ var init_long_term = __esm({
155808
156202
  }
155809
156203
  });
155810
156204
 
156205
+ // src/knowledge/governor.ts
156206
+ function clampRelevance(value) {
156207
+ if (!Number.isFinite(value)) return 0;
156208
+ return Math.max(0, Math.min(1, value));
156209
+ }
156210
+ function classify(candidate) {
156211
+ const freshness = candidate.freshness ?? "unknown";
156212
+ const trust = candidate.trust ?? "historical";
156213
+ const quality = candidate.quality ?? "probationary";
156214
+ const conflict = candidate.conflict ?? "none";
156215
+ if (!candidate.scopeAllowed) {
156216
+ return { disposition: "exclude", reasons: ["scope-forbidden"] };
156217
+ }
156218
+ if (conflict === "confirmed") {
156219
+ return { disposition: "exclude", reasons: ["confirmed-conflict"] };
156220
+ }
156221
+ if (quality === "blocked") {
156222
+ return { disposition: "exclude", reasons: ["blocked-quality"] };
156223
+ }
156224
+ if (quality === "degraded") {
156225
+ return { disposition: "defer", reasons: ["degraded-quality"] };
156226
+ }
156227
+ if (freshness === "stale") {
156228
+ return { disposition: "defer", reasons: ["stale-evidence"] };
156229
+ }
156230
+ const reasons = [];
156231
+ let disposition = "include";
156232
+ if (freshness === "unknown") {
156233
+ disposition = "compact";
156234
+ reasons.push("unknown-freshness");
156235
+ }
156236
+ if (conflict === "possible") {
156237
+ disposition = "compact";
156238
+ reasons.push("possible-conflict");
156239
+ }
156240
+ if (quality === "probationary") {
156241
+ disposition = "compact";
156242
+ reasons.push("probationary-evidence");
156243
+ }
156244
+ if (disposition === "include" && freshness === "current" && trust === "source-backed") {
156245
+ reasons.push("current-source-backed-evidence");
156246
+ } else if (reasons.length === 0) {
156247
+ reasons.push("relevant-evidence");
156248
+ }
156249
+ return { disposition, reasons };
156250
+ }
156251
+ function priority(decision) {
156252
+ const dispositionWeight = {
156253
+ include: 3,
156254
+ compact: 2,
156255
+ defer: 1,
156256
+ exclude: 0
156257
+ };
156258
+ const evidence = Math.min(3, decision.candidate.evidenceCount ?? 0) / 10;
156259
+ return dispositionWeight[decision.disposition] + clampRelevance(decision.candidate.relevance) + evidence;
156260
+ }
156261
+ function governContextCandidates(candidates, maxTokens) {
156262
+ const safeBudget = Math.max(0, Math.floor(maxTokens));
156263
+ const decisions = candidates.map((candidate) => ({ candidate, ...classify(candidate) }));
156264
+ const eligible = decisions.filter((decision) => decision.disposition === "include" || decision.disposition === "compact").sort((left, right) => priority(right) - priority(left));
156265
+ let usedTokens = 0;
156266
+ for (const decision of eligible) {
156267
+ const tokens = Math.max(0, Math.ceil(decision.candidate.estimatedTokens));
156268
+ if (usedTokens + tokens <= safeBudget) {
156269
+ usedTokens += tokens;
156270
+ continue;
156271
+ }
156272
+ decision.disposition = "defer";
156273
+ decision.reasons = [...decision.reasons, "token-budget"];
156274
+ }
156275
+ const delivered = decisions.filter((decision) => decision.disposition === "include" || decision.disposition === "compact");
156276
+ const mode = delivered.length === 0 ? "abstain" : delivered.some((decision) => decision.disposition === "include") ? "workset" : "card";
156277
+ const cautions = [...new Set(decisions.filter((decision) => decision.disposition !== "include").flatMap((decision) => decision.reasons))];
156278
+ return {
156279
+ mode,
156280
+ budget: { maxTokens: safeBudget, usedTokens },
156281
+ decisions,
156282
+ cautions: cautions.length > 0 ? cautions : ["no-qualified-evidence"]
156283
+ };
156284
+ }
156285
+ var init_governor = __esm({
156286
+ "src/knowledge/governor.ts"() {
156287
+ "use strict";
156288
+ init_esm_shims();
156289
+ }
156290
+ });
156291
+
155811
156292
  // src/knowledge/workset.ts
155812
156293
  function unique(values) {
155813
156294
  return [...new Set(values.filter(Boolean))];
155814
156295
  }
155815
- function short(text, budget = 28) {
155816
- const safe = sanitizeCredentials(text).replace(/\s+/g, " ").trim();
156296
+ function short(text2, budget = 28) {
156297
+ const safe = sanitizeCredentials(text2).replace(/\s+/g, " ").trim();
155817
156298
  return countTextTokens(safe) <= budget ? safe : truncateToTokenBudget(safe, budget);
155818
156299
  }
155819
156300
  function claimAssertion(claim) {
@@ -155944,6 +156425,65 @@ function receiptOmissions(omitted, hiddenCautionMemoryCount) {
155944
156425
  function scheduledActions(cautions) {
155945
156426
  return cautions.filter((caution) => caution.kind === "codegraph-refresh-queued").map((caution) => short(caution.message, 28));
155946
156427
  }
156428
+ function isGovernedDelivery(disposition) {
156429
+ return disposition === "include" || disposition === "compact";
156430
+ }
156431
+ function governOptionalArtifacts(input) {
156432
+ const candidates = [
156433
+ ...input.reliableMemory.map((memory, index) => ({
156434
+ kind: "memory",
156435
+ id: "memory:" + memory.id,
156436
+ estimatedTokens: 10,
156437
+ relevance: Math.max(0.2, 0.9 - index * 0.1),
156438
+ scopeAllowed: true,
156439
+ freshness: freshnessForMemory(memory.status),
156440
+ trust: "historical",
156441
+ quality: memory.status === "current" ? "verified" : "degraded"
156442
+ })),
156443
+ ...input.claims.map((claim, index) => ({
156444
+ kind: "claim",
156445
+ id: "claim:" + claim.id,
156446
+ estimatedTokens: 12,
156447
+ relevance: Math.max(0.2, 0.95 - index * 0.1),
156448
+ scopeAllowed: true,
156449
+ freshness: claim.status === "active" ? "current" : "unknown",
156450
+ trust: "source-backed",
156451
+ quality: claim.reviewState === "approved" ? "verified" : "probationary",
156452
+ conflict: claim.status === "disputed" ? "confirmed" : "none",
156453
+ evidenceCount: claim.evidenceRefs.length
156454
+ })),
156455
+ ...input.durableMemory.map((memory, index) => ({
156456
+ kind: "durable-memory",
156457
+ id: "durable:" + memory.id,
156458
+ estimatedTokens: 14,
156459
+ relevance: Math.max(0.2, 0.8 - index * 0.1),
156460
+ scopeAllowed: true,
156461
+ freshness: memory.state === "approved" ? "current" : "unknown",
156462
+ trust: "source-backed",
156463
+ quality: memory.quality,
156464
+ evidenceCount: memory.evidenceRefs.length
156465
+ })),
156466
+ ...input.workflows.map((workflow, index) => ({
156467
+ kind: "workflow",
156468
+ id: "workflow:" + workflow.id,
156469
+ estimatedTokens: 14,
156470
+ relevance: Math.max(0.2, 0.85 - index * 0.1),
156471
+ scopeAllowed: true,
156472
+ freshness: "current",
156473
+ trust: "source-backed",
156474
+ quality: "verified"
156475
+ }))
156476
+ ];
156477
+ const plan = governContextCandidates(candidates, Number.MAX_SAFE_INTEGER);
156478
+ const permitted = new Set(plan.decisions.filter((decision) => isGovernedDelivery(decision.disposition)).map((decision) => decision.candidate.id));
156479
+ return {
156480
+ plan,
156481
+ reliableMemory: input.reliableMemory.filter((memory) => permitted.has("memory:" + memory.id)),
156482
+ claims: input.claims.filter((claim) => permitted.has("claim:" + claim.id)),
156483
+ durableMemory: input.durableMemory.filter((memory) => permitted.has("durable:" + memory.id)),
156484
+ workflows: input.workflows.filter((workflow) => permitted.has("workflow:" + workflow.id))
156485
+ };
156486
+ }
155947
156487
  function renderTaskWorksetPrompt(input) {
155948
156488
  const maxTokens = input.budget?.maxTokens ?? 180;
155949
156489
  const omitted = [];
@@ -156071,6 +156611,56 @@ function renderTaskWorksetPrompt(input) {
156071
156611
  trust: "source-backed"
156072
156612
  });
156073
156613
  }
156614
+ if (input.codeEvolution && input.codeEvolution.changes.length > 0) {
156615
+ appendLine(lines, "", maxTokens, omitted, "code-evolution-heading");
156616
+ appendLine(lines, "Code changes since prior scan", maxTokens, omitted, "code-evolution-heading");
156617
+ for (const change of input.codeEvolution.changes.slice(0, 3)) {
156618
+ appendLine(
156619
+ lines,
156620
+ "- " + change.kind + ": " + change.path,
156621
+ maxTokens,
156622
+ omitted,
156623
+ "code-evolution-change",
156624
+ selected,
156625
+ {
156626
+ kind: "code-state",
156627
+ id: "snapshot:" + input.codeEvolution.toSnapshotId,
156628
+ reason: "exact file hash change between complete CodeGraph snapshots",
156629
+ freshness: "current",
156630
+ trust: "source-backed"
156631
+ }
156632
+ );
156633
+ }
156634
+ for (const path36 of input.codeEvolution.directlyConnectedPaths.slice(0, 2)) {
156635
+ appendLine(
156636
+ lines,
156637
+ "- connected now: " + path36,
156638
+ maxTokens,
156639
+ omitted,
156640
+ "code-evolution-impact",
156641
+ selected,
156642
+ {
156643
+ kind: "code-state",
156644
+ id: "snapshot:" + input.codeEvolution.toSnapshotId,
156645
+ reason: "bounded current CodeGraph impact relation",
156646
+ freshness: "current",
156647
+ trust: "derived"
156648
+ }
156649
+ );
156650
+ }
156651
+ if ((input.codeEvolution.affectedMemoryCount ?? 0) > 0) {
156652
+ appendLine(
156653
+ lines,
156654
+ "- " + input.codeEvolution.affectedMemoryCount + " stored memory link(s) reference this changed code; reread source before relying on their conclusions.",
156655
+ maxTokens,
156656
+ omitted,
156657
+ "code-evolution-stale-memory"
156658
+ );
156659
+ }
156660
+ if (input.codeEvolution.truncated) {
156661
+ appendLine(lines, "- More connected files exist; inspect CodeGraph before assuming complete impact.", maxTokens, omitted, "code-evolution-truncated");
156662
+ }
156663
+ }
156074
156664
  if (input.semanticCode && (input.semanticCode.entryPoints.length > 0 || input.semanticCode.relations.length > 0)) {
156075
156665
  appendLine(lines, "", maxTokens, omitted, "semantic-code-heading");
156076
156666
  appendLine(lines, "Semantic code outline", maxTokens, omitted, "semantic-code-heading");
@@ -156261,6 +156851,17 @@ async function buildTaskWorkset(input) {
156261
156851
  }));
156262
156852
  let durableMemory = [];
156263
156853
  let durableEvidence = [];
156854
+ let outcomeStore;
156855
+ try {
156856
+ outcomeStore = new OutcomeStore();
156857
+ await outcomeStore.init(input.dataDir);
156858
+ } catch {
156859
+ }
156860
+ const claimQuality = outcomeStore ? outcomeStore.latestForCandidates(input.projectId, "claim", claims.map((claim) => claim.id)) : /* @__PURE__ */ new Map();
156861
+ for (const claim of claims) {
156862
+ const outcomeQuality = qualityFromOutcome(claimQuality.get(claim.id));
156863
+ if (outcomeQuality === "degraded") claim.reviewState = "needs-review";
156864
+ }
156264
156865
  if (task) {
156265
156866
  try {
156266
156867
  const selected = await selectLongTermMemoriesForTask({
@@ -156271,11 +156872,13 @@ async function buildTaskWorkset(input) {
156271
156872
  ...input.reader?.isTeamMember ? { isTeamMember: true } : {},
156272
156873
  limit: 3
156273
156874
  });
156875
+ const durableQuality = outcomeStore ? outcomeStore.latestForCandidates(input.projectId, "durable-memory", selected.map((item) => item.memory.id)) : /* @__PURE__ */ new Map();
156274
156876
  durableMemory = selected.map((item) => ({
156275
156877
  id: item.memory.id,
156276
156878
  kind: item.memory.kind,
156277
156879
  scope: item.memory.scope,
156278
156880
  state: item.memory.state,
156881
+ quality: qualityFromOutcome(durableQuality.get(item.memory.id)) ?? (item.memory.state === "approved" ? "verified" : "probationary"),
156279
156882
  title: item.memory.title,
156280
156883
  summary: renderLongTermMemorySummary(item.memory, 20),
156281
156884
  evidenceRefs: item.evidence.map((evidence) => evidence.id),
@@ -156321,18 +156924,25 @@ async function buildTaskWorkset(input) {
156321
156924
  }
156322
156925
  } catch {
156323
156926
  }
156324
- const evidenceIds = unique(selection.claims.flatMap((claim) => evidenceIdsForClaim(
156325
- claim,
156326
- evidenceByClaim.get(claim.id) ?? []
156327
- )).concat(
156328
- durableMemory.map((memory) => "durable:" + memory.id),
156329
- durableEvidence.map((evidence) => "durable-evidence:" + evidence.id)
156330
- ));
156331
156927
  const verification = unique([
156332
156928
  ...workflows.flatMap((workflow) => workflow.verificationGates),
156333
156929
  ...input.verificationHints
156334
156930
  ]).slice(0, 4);
156335
156931
  const normalizedCautions = unique(cautions.map((caution) => caution.kind)).map((kind) => cautions.find((caution) => caution.kind === kind)).slice(0, 6);
156932
+ const governed = governOptionalArtifacts({
156933
+ reliableMemory: input.reliableMemory?.slice(0, 3) ?? [],
156934
+ claims,
156935
+ durableMemory,
156936
+ workflows
156937
+ });
156938
+ const governedDurableIds = new Set(governed.durableMemory.map((memory) => memory.id));
156939
+ const evidenceIds = unique(governed.claims.flatMap((claim) => evidenceIdsForClaim(
156940
+ claim,
156941
+ evidenceByClaim.get(claim.id) ?? []
156942
+ )).concat(
156943
+ governed.durableMemory.map((memory) => "durable:" + memory.id),
156944
+ durableEvidence.filter((evidence) => governedDurableIds.has(evidence.memoryId)).map((evidence) => "durable-evidence:" + evidence.id)
156945
+ ));
156336
156946
  const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0 || input.continuation.compactCheckpoint) ? {
156337
156947
  ...input.continuation.previousSession ? {
156338
156948
  previousSession: {
@@ -156359,15 +156969,16 @@ async function buildTaskWorkset(input) {
156359
156969
  currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
156360
156970
  ...continuation ? { continuation } : {},
156361
156971
  ...input.codeState ? { codeState: short(input.codeState, 28) } : {},
156972
+ ...input.codeEvolution ? { codeEvolution: input.codeEvolution } : {},
156362
156973
  startHere: unique(input.startHere).slice(0, 5),
156363
156974
  ...input.semanticCode ? { semanticCode: input.semanticCode } : {},
156364
- reliableMemory: input.reliableMemory?.slice(0, 3) ?? [],
156975
+ reliableMemory: governed.reliableMemory,
156365
156976
  cautionMemory: input.cautionMemory?.slice(0, 3) ?? [],
156366
156977
  hiddenCautionMemoryCount: input.hiddenCautionMemoryCount ?? 0,
156367
- claims,
156368
- pages,
156369
- durableMemory,
156370
- workflows,
156978
+ claims: governed.claims,
156979
+ pages: pages.filter((page) => page.claimIds.some((claimId) => governed.claims.some((claim) => claim.id === claimId))),
156980
+ durableMemory: governed.durableMemory,
156981
+ workflows: governed.workflows,
156371
156982
  cautions: normalizedCautions,
156372
156983
  verification,
156373
156984
  evidenceIds,
@@ -156392,6 +157003,17 @@ async function buildTaskWorkset(input) {
156392
157003
  },
156393
157004
  selected: rendered.selected,
156394
157005
  omitted: receiptOmissions(rendered.omittedItems, base.hiddenCautionMemoryCount),
157006
+ governance: {
157007
+ scope: "optional-evidence",
157008
+ mode: governed.plan.mode,
157009
+ decisions: governed.plan.decisions.map((decision) => ({
157010
+ kind: decision.candidate.kind,
157011
+ ...decision.candidate.id ? { id: decision.candidate.id } : {},
157012
+ disposition: decision.disposition,
157013
+ reasons: decision.reasons
157014
+ })),
157015
+ cautions: governed.plan.cautions
157016
+ },
156395
157017
  scheduledActions: scheduledActions(normalizedCautions)
156396
157018
  };
156397
157019
  return {
@@ -156417,8 +157039,11 @@ var init_workset = __esm({
156417
157039
  init_workspace_store();
156418
157040
  init_workspace();
156419
157041
  init_workflow_store();
157042
+ init_outcome_store();
157043
+ init_outcome_types();
156420
157044
  init_workflows2();
156421
157045
  init_long_term();
157046
+ init_governor();
156422
157047
  CONTINUATION_DETAIL_TOKEN_BUDGET = 20;
156423
157048
  }
156424
157049
  });
@@ -156441,19 +157066,19 @@ function readTextIfExists(filePath) {
156441
157066
  }
156442
157067
  }
156443
157068
  function readPackageVersion(rootPath) {
156444
- const text = readTextIfExists(path26.join(rootPath, "package.json"));
156445
- if (!text) return void 0;
157069
+ const text2 = readTextIfExists(path26.join(rootPath, "package.json"));
157070
+ if (!text2) return void 0;
156446
157071
  try {
156447
- const parsed = JSON.parse(text);
157072
+ const parsed = JSON.parse(text2);
156448
157073
  return typeof parsed.version === "string" ? parsed.version : void 0;
156449
157074
  } catch {
156450
157075
  return void 0;
156451
157076
  }
156452
157077
  }
156453
157078
  function readLatestChangelog(rootPath) {
156454
- const text = readTextIfExists(path26.join(rootPath, "CHANGELOG.md"));
156455
- if (!text) return void 0;
156456
- const match2 = text.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
157079
+ const text2 = readTextIfExists(path26.join(rootPath, "CHANGELOG.md"));
157080
+ if (!text2) return void 0;
157081
+ const match2 = text2.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
156457
157082
  if (!match2) return void 0;
156458
157083
  return {
156459
157084
  version: match2[1],
@@ -156516,6 +157141,7 @@ function compareDateStrings(a, b) {
156516
157141
  }
156517
157142
  function detectStaleProgressNotes(input) {
156518
157143
  const candidates = [
157144
+ "ACTIVE_WORK.md",
156519
157145
  "progress.txt",
156520
157146
  "docs/dev-log/progress.txt",
156521
157147
  "docs/memcode/dev-log/progress.txt"
@@ -156653,6 +157279,7 @@ function providerQuality(input) {
156653
157279
  capabilities: {
156654
157280
  declarations: true,
156655
157281
  importHints: true,
157282
+ localRelativeImportTargets: true,
156656
157283
  resolvedRelations: false,
156657
157284
  exactLocations: false
156658
157285
  },
@@ -157174,8 +157801,8 @@ var compaction_checkpoint_store_exports = {};
157174
157801
  __export(compaction_checkpoint_store_exports, {
157175
157802
  CompactionCheckpointStore: () => CompactionCheckpointStore
157176
157803
  });
157177
- import { createHash as createHash14, randomUUID as randomUUID13 } from "crypto";
157178
- function optionalText6(value) {
157804
+ import { createHash as createHash14, randomUUID as randomUUID14 } from "crypto";
157805
+ function optionalText7(value) {
157179
157806
  return typeof value === "string" && value ? value : void 0;
157180
157807
  }
157181
157808
  function optionalNumber2(value) {
@@ -157229,15 +157856,15 @@ function rowToCheckpoint(row) {
157229
157856
  reason: row.reason,
157230
157857
  sourceEvent: row.source_event,
157231
157858
  sourceKey: row.source_key,
157232
- ...optionalText6(row.summary) ? { summary: row.summary } : {},
157859
+ ...optionalText7(row.summary) ? { summary: row.summary } : {},
157233
157860
  ...optionalNumber2(row.tokens_before) !== void 0 ? { tokensBefore: Number(row.tokens_before) } : {},
157234
- ...optionalText6(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
157861
+ ...optionalText7(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
157235
157862
  ...parseDetails(row.details_json) ? { details: parseDetails(row.details_json) } : {},
157236
157863
  transcriptAvailable: Boolean(row.transcript_available),
157237
157864
  status: row.status,
157238
157865
  preCapturedAt: row.pre_captured_at,
157239
- ...optionalText6(row.completed_at) ? { completedAt: row.completed_at } : {},
157240
- ...optionalText6(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
157866
+ ...optionalText7(row.completed_at) ? { completedAt: row.completed_at } : {},
157867
+ ...optionalText7(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
157241
157868
  deliveryCount: Number(row.delivery_count ?? 0),
157242
157869
  createdAt: row.created_at,
157243
157870
  updatedAt: row.updated_at
@@ -157275,7 +157902,7 @@ var init_compaction_checkpoint_store = __esm({
157275
157902
  if (pending) return rowToCheckpoint(pending);
157276
157903
  const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
157277
157904
  const checkpoint = {
157278
- id: randomUUID13(),
157905
+ id: randomUUID14(),
157279
157906
  projectId: input.projectId,
157280
157907
  sessionId: input.sessionId,
157281
157908
  agent: input.agent,
@@ -157283,7 +157910,7 @@ var init_compaction_checkpoint_store = __esm({
157283
157910
  captureKind: "preflight",
157284
157911
  reason: safeReason(input.reason),
157285
157912
  sourceEvent: input.sourceEvent,
157286
- sourceKey: `pre:${randomUUID13()}`,
157913
+ sourceKey: `pre:${randomUUID14()}`,
157287
157914
  transcriptAvailable: Boolean(input.transcriptAvailable),
157288
157915
  status: "active",
157289
157916
  preCapturedAt: now3,
@@ -157349,7 +157976,7 @@ var init_compaction_checkpoint_store = __esm({
157349
157976
  return this.get(checkpoint2.id);
157350
157977
  }
157351
157978
  const checkpoint = {
157352
- id: randomUUID13(),
157979
+ id: randomUUID14(),
157353
157980
  projectId: input.projectId,
157354
157981
  sessionId: input.sessionId,
157355
157982
  agent: input.agent,
@@ -157611,6 +158238,25 @@ async function buildAutoProjectContext(input) {
157611
158238
  const overview = explain.overview;
157612
158239
  const currentFacts = collectCurrentProjectFacts({ project: input.project, now: now3 });
157613
158240
  const latestSnapshot = overview.code.latestSnapshot;
158241
+ let codeEvolution;
158242
+ if (continuationRequested && latestSnapshot?.previousSnapshotId && latestSnapshot.changedPathCount > 0) {
158243
+ const diff = store.diffSnapshots(input.project.id, latestSnapshot.previousSnapshotId, latestSnapshot.id);
158244
+ if (diff.available && diff.changes.length > 0) {
158245
+ const impact = store.impactSlice(input.project.id, diff.changes.map((change) => change.path));
158246
+ const changedFileIds = new Set([
158247
+ ...store.listSnapshotFiles(diff.fromSnapshotId),
158248
+ ...store.listSnapshotFiles(diff.toSnapshotId)
158249
+ ].filter((file) => diff.changes.some((change) => change.path === file.path)).map((file) => file.fileId));
158250
+ codeEvolution = {
158251
+ fromSnapshotId: diff.fromSnapshotId,
158252
+ toSnapshotId: diff.toSnapshotId,
158253
+ changes: diff.changes.slice(0, 5).map((change) => ({ path: change.path, kind: change.kind })),
158254
+ directlyConnectedPaths: impact.directlyConnectedPaths.slice(0, 3),
158255
+ affectedMemoryCount: store.countStaleObservationRefsForFiles(input.project.id, [...changedFileIds]),
158256
+ truncated: impact.truncated || diff.changes.length > 5
158257
+ };
158258
+ }
158259
+ }
157614
158260
  const sourceSets = lensSourceSets({ task, lens, explain });
157615
158261
  let externalOutline;
157616
158262
  let externalCaution;
@@ -157687,6 +158333,7 @@ async function buildAutoProjectContext(input) {
157687
158333
  currentFacts: worksetFactLines(currentFacts),
157688
158334
  ...continuation ? { continuation } : {},
157689
158335
  codeState: codeStateLine(overview),
158336
+ ...codeEvolution ? { codeEvolution } : {},
157690
158337
  reliableMemory: sourceSets.reliableSources.slice(0, lens.sourceLimit).map((source) => ({
157691
158338
  id: source.observationId,
157692
158339
  title: source.title,
@@ -157738,9 +158385,9 @@ async function buildAutoProjectContext(input) {
157738
158385
  function formatLanguages(overview) {
157739
158386
  return overview.code.languages.length > 0 ? overview.code.languages.map((item) => `${item.language} ${item.files}`).join(", ") : "none indexed yet";
157740
158387
  }
157741
- function compactContinuationText(text, budget) {
158388
+ function compactContinuationText(text2, budget) {
157742
158389
  return truncateToTokenBudget(
157743
- sanitizeCredentials(text).replace(/\s+/g, " ").trim(),
158390
+ sanitizeCredentials(text2).replace(/\s+/g, " ").trim(),
157744
158391
  budget
157745
158392
  );
157746
158393
  }
@@ -158015,8 +158662,8 @@ __export(context_pack_exports, {
158015
158662
  function uniq2(items) {
158016
158663
  return [...new Set(items)];
158017
158664
  }
158018
- function tokenize4(text) {
158019
- return (text.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1);
158665
+ function tokenize4(text2) {
158666
+ return (text2.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1);
158020
158667
  }
158021
158668
  function timestampOf(observation) {
158022
158669
  return Date.parse(observation.updatedAt ?? observation.createdAt ?? "") || 0;
@@ -158618,7 +159265,7 @@ __export(team_store_exports, {
158618
159265
  isTeamStoreInitialized: () => isTeamStoreInitialized,
158619
159266
  resetTeamStore: () => resetTeamStore
158620
159267
  });
158621
- import { randomUUID as randomUUID14 } from "crypto";
159268
+ import { randomUUID as randomUUID15 } from "crypto";
158622
159269
  import path28 from "path";
158623
159270
  import fs18 from "fs";
158624
159271
  function getTeamStore() {
@@ -158907,7 +159554,7 @@ var init_team_store = __esm({
158907
159554
  * reactivate it (preserving agent_id). Otherwise create a new one.
158908
159555
  */
158909
159556
  registerAgent(input) {
158910
- const instanceId = input.instanceId || randomUUID14();
159557
+ const instanceId = input.instanceId || randomUUID15();
158911
159558
  const now3 = Date.now();
158912
159559
  const existing = this.stmtAgentFindByInstance.get(
158913
159560
  input.projectId,
@@ -158933,7 +159580,7 @@ var init_team_store = __esm({
158933
159580
  this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
158934
159581
  return row2;
158935
159582
  }
158936
- const agentId = randomUUID14();
159583
+ const agentId = randomUUID15();
158937
159584
  this.stmtAgentUpsert.run({
158938
159585
  agent_id: agentId,
158939
159586
  project_id: input.projectId,
@@ -159035,7 +159682,7 @@ var init_team_store = __esm({
159035
159682
  return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
159036
159683
  }
159037
159684
  }
159038
- const id = randomUUID14();
159685
+ const id = randomUUID15();
159039
159686
  const now3 = Date.now();
159040
159687
  const row = {
159041
159688
  id,
@@ -159085,7 +159732,7 @@ var init_team_store = __esm({
159085
159732
  // Task Operations (with atomic claim semantics)
159086
159733
  // ═══════════════════════════════════════════════════════════════════
159087
159734
  createTask(input) {
159088
- const taskId = randomUUID14();
159735
+ const taskId = randomUUID15();
159089
159736
  const now3 = Date.now();
159090
159737
  const row = {
159091
159738
  task_id: taskId,
@@ -159357,7 +160004,7 @@ var init_team_store = __esm({
159357
160004
  for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
159358
160005
  for (const msg of msgs) {
159359
160006
  this.stmtMsgInsert.run({
159360
- id: msg.id ?? randomUUID14(),
160007
+ id: msg.id ?? randomUUID15(),
159361
160008
  project_id: "migrated",
159362
160009
  sender_agent_id: msg.from ?? "unknown",
159363
160010
  recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
@@ -159630,19 +160277,19 @@ function buildCompactionWorkset(checkpoint, options = {}) {
159630
160277
  const source = sanitizeCredentials(checkpoint.summary?.trim() || fallback);
159631
160278
  const available = Math.max(0, budget - countTextTokens(header) - 4);
159632
160279
  let excerpt = source ? truncateToTokenBudget(source, available) : "";
159633
- let text = `${header}${excerpt ? `### Host checkpoint
160280
+ let text2 = `${header}${excerpt ? `### Host checkpoint
159634
160281
  ${excerpt}` : ""}`.trim();
159635
- while (excerpt && countTextTokens(text) > budget) {
160282
+ while (excerpt && countTextTokens(text2) > budget) {
159636
160283
  const nextExcerptBudget = Math.max(1, Math.floor(countTextTokens(excerpt) * 0.8));
159637
160284
  excerpt = truncateToTokenBudget(excerpt, nextExcerptBudget);
159638
- text = `${header}${excerpt ? `### Host checkpoint
160285
+ text2 = `${header}${excerpt ? `### Host checkpoint
159639
160286
  ${excerpt}` : ""}`.trim();
159640
160287
  }
159641
- if (countTextTokens(text) > budget) text = truncateToTokenBudget(text, budget);
160288
+ if (countTextTokens(text2) > budget) text2 = truncateToTokenBudget(text2, budget);
159642
160289
  return {
159643
160290
  checkpointId: checkpoint.id,
159644
- text,
159645
- tokens: countTextTokens(text)
160291
+ text: text2,
160292
+ tokens: countTextTokens(text2)
159646
160293
  };
159647
160294
  }
159648
160295
  function sourceEvent(input) {
@@ -161533,15 +162180,15 @@ function validateSemantics(graph) {
161533
162180
  return warnings;
161534
162181
  }
161535
162182
  function extractJson(raw) {
161536
- let text = raw;
162183
+ let text2 = raw;
161537
162184
  try {
161538
162185
  const envelope = JSON.parse(raw.trim());
161539
162186
  if (envelope && typeof envelope.result === "string" && envelope.type === "result") {
161540
- text = envelope.result;
162187
+ text2 = envelope.result;
161541
162188
  }
161542
162189
  } catch {
161543
162190
  }
161544
- if (text === raw && raw.includes('"type"')) {
162191
+ if (text2 === raw && raw.includes('"type"')) {
161545
162192
  const textBlocks = [];
161546
162193
  for (const line of raw.split("\n")) {
161547
162194
  const trimmed = line.trim();
@@ -161565,27 +162212,27 @@ function extractJson(raw) {
161565
162212
  }
161566
162213
  }
161567
162214
  if (textBlocks.length > 0) {
161568
- text = textBlocks.join("");
162215
+ text2 = textBlocks.join("");
161569
162216
  }
161570
162217
  }
161571
- const fenced = text.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
162218
+ const fenced = text2.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
161572
162219
  if (fenced) {
161573
162220
  const candidate = fenced[1].trim();
161574
162221
  if (candidate.startsWith("{")) return candidate;
161575
162222
  }
161576
- const braceStart = text.indexOf("{");
162223
+ const braceStart = text2.indexOf("{");
161577
162224
  if (braceStart !== -1) {
161578
- const extracted = extractBalancedJson(text, braceStart);
162225
+ const extracted = extractBalancedJson(text2, braceStart);
161579
162226
  if (extracted) return extracted;
161580
162227
  }
161581
162228
  return null;
161582
162229
  }
161583
- function extractBalancedJson(text, startIdx) {
162230
+ function extractBalancedJson(text2, startIdx) {
161584
162231
  let depth = 0;
161585
162232
  let inString = false;
161586
162233
  let escape2 = false;
161587
- for (let i2 = startIdx; i2 < text.length; i2++) {
161588
- const ch = text[i2];
162234
+ for (let i2 = startIdx; i2 < text2.length; i2++) {
162235
+ const ch = text2[i2];
161589
162236
  if (escape2) {
161590
162237
  escape2 = false;
161591
162238
  continue;
@@ -161603,7 +162250,7 @@ function extractBalancedJson(text, startIdx) {
161603
162250
  else if (ch === "}") {
161604
162251
  depth--;
161605
162252
  if (depth === 0) {
161606
- return text.slice(startIdx, i2 + 1);
162253
+ return text2.slice(startIdx, i2 + 1);
161607
162254
  }
161608
162255
  }
161609
162256
  }
@@ -161822,7 +162469,7 @@ __export(planner_exports, {
161822
162469
  materializeTaskGraph: () => materializeTaskGraph,
161823
162470
  seedAutonomousPipeline: () => seedAutonomousPipeline
161824
162471
  });
161825
- import { randomUUID as randomUUID15 } from "crypto";
162472
+ import { randomUUID as randomUUID16 } from "crypto";
161826
162473
  function isPlannerTask(metadata) {
161827
162474
  if (!metadata) return null;
161828
162475
  try {
@@ -161880,7 +162527,7 @@ function seedAutonomousPipeline(teamStore, projectId, config, opts) {
161880
162527
  const maxIterations = config.maxIterations ?? 3;
161881
162528
  const taskBudget = config.taskBudget ?? 15;
161882
162529
  const structuredPlan = opts?.structuredPlan ?? true;
161883
- const pipelineId = randomUUID15();
162530
+ const pipelineId = randomUUID16();
161884
162531
  const meta = {
161885
162532
  plannerType: "plan",
161886
162533
  pipelineId,
@@ -162325,8 +162972,8 @@ async function callVisionLLM(systemPrompt, imageBase64, mimeType) {
162325
162972
  return data.choices[0]?.message?.content ?? "";
162326
162973
  }
162327
162974
  function normalizeText4(value, fallback = "") {
162328
- const text = typeof value === "string" && value.trim() ? value.trim() : fallback;
162329
- return sanitizeCredentials(text).slice(0, MAX_VISION_DESCRIPTION_CHARS);
162975
+ const text2 = typeof value === "string" && value.trim() ? value.trim() : fallback;
162976
+ return sanitizeCredentials(text2).slice(0, MAX_VISION_DESCRIPTION_CHARS);
162330
162977
  }
162331
162978
  function normalizeLabels(value) {
162332
162979
  if (!Array.isArray(value)) return [];
@@ -164315,7 +164962,7 @@ The path should point to a directory containing a .git folder.`
164315
164962
  };
164316
164963
  const server = existingServer ?? new McpServer({
164317
164964
  name: "memorix",
164318
- version: true ? "1.4.0" : "1.0.1"
164965
+ version: true ? "1.4.2" : "1.0.1"
164319
164966
  });
164320
164967
  const originalRegisterTool = server.registerTool.bind(server);
164321
164968
  server.registerTool = ((name, ...args) => {
@@ -165051,10 +165698,10 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
165051
165698
  const duplicate = blockCoveredAutopilotEvidence("memorix_search", result.entries.map((entry) => entry.id), force);
165052
165699
  if (duplicate) return duplicate;
165053
165700
  }
165054
- let text = result.formatted;
165701
+ let text2 = result.formatted;
165055
165702
  try {
165056
165703
  const { getLastSearchMode: getLastSearchMode2 } = await Promise.resolve().then(() => (init_orama_store(), orama_store_exports));
165057
- text += `
165704
+ text2 += `
165058
165705
 
165059
165706
  _Search mode: ${getLastSearchMode2(project.id)}_`;
165060
165707
  } catch {
@@ -165063,7 +165710,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165063
165710
  content: [
165064
165711
  {
165065
165712
  type: "text",
165066
- text
165713
+ text: text2
165067
165714
  }
165068
165715
  ]
165069
165716
  };
@@ -165096,14 +165743,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165096
165743
  query,
165097
165744
  limit: limit2 != null ? coerceNumber(limit2, 5) : void 0
165098
165745
  });
165099
- const text = format === "summary" ? [
165746
+ const text2 = format === "summary" ? [
165100
165747
  `Graph context packet for ${project.name}`,
165101
165748
  `- ${packet.summary}`,
165102
165749
  "",
165103
165750
  ...packet.entities.map((entity) => `* ${entity.name} (#${entity.observationIds.join(", #")})`)
165104
165751
  ].join("\n") : formatGraphContextPrompt(packet);
165105
165752
  return {
165106
- content: [{ type: "text", text }]
165753
+ content: [{ type: "text", text: text2 }]
165107
165754
  };
165108
165755
  }
165109
165756
  );
@@ -165163,7 +165810,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165163
165810
  });
165164
165811
  }
165165
165812
  });
165166
- const text = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
165813
+ const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
165167
165814
  autopilotRetrievalBoundary = {
165168
165815
  projectId: project.id,
165169
165816
  issuedAt: Date.now(),
@@ -165175,7 +165822,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165175
165822
  readOnly: READ_ONLY_TASK_PATTERN.test(task ?? "")
165176
165823
  };
165177
165824
  return {
165178
- content: [{ type: "text", text }]
165825
+ content: [{ type: "text", text: text2 }]
165179
165826
  };
165180
165827
  }
165181
165828
  );
@@ -165303,9 +165950,9 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165303
165950
  ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
165304
165951
  reader: getObservationReader()
165305
165952
  });
165306
- const text = buildContextPackPrompt2(pack);
165953
+ const text2 = buildContextPackPrompt2(pack);
165307
165954
  return {
165308
- content: [{ type: "text", text }]
165955
+ content: [{ type: "text", text: text2 }]
165309
165956
  };
165310
165957
  }
165311
165958
  );
@@ -165367,7 +166014,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165367
166014
  }) => {
165368
166015
  const unresolved = requireResolvedProject("manage the Knowledge Workspace for the current project");
165369
166016
  if (unresolved) return unresolved;
165370
- const text = (value, isError = false) => ({
166017
+ const text2 = (value, isError = false) => ({
165371
166018
  content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
165372
166019
  ...isError ? { isError: true } : {}
165373
166020
  });
@@ -165404,7 +166051,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165404
166051
  ]);
165405
166052
  if (action === "workspace_init") {
165406
166053
  if (modeValue === "versioned" && !requireText(workspacePath, "path")) {
165407
- return text({ error: "path is required to initialize a versioned Knowledge Workspace." }, true);
166054
+ return text2({ error: "path is required to initialize a versioned Knowledge Workspace." }, true);
165408
166055
  }
165409
166056
  const workspace2 = await initializeKnowledgeWorkspace2({
165410
166057
  projectId: project.id,
@@ -165412,7 +166059,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165412
166059
  mode: modeValue,
165413
166060
  ...modeValue === "versioned" ? { projectRoot: project.rootPath, rootPath: requireText(workspacePath, "path") } : {}
165414
166061
  });
165415
- return text({
166062
+ return text2({
165416
166063
  workspace: {
165417
166064
  id: workspace2.id,
165418
166065
  mode: workspace2.mode,
@@ -165424,7 +166071,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165424
166071
  }
165425
166072
  const workspace = await loadKnowledgeWorkspace2({ projectId: project.id, dataDir: projectDir2, mode: modeValue });
165426
166073
  if (!workspace) {
165427
- return text({ error: "Knowledge Workspace is not initialized. Run workspace_init first." }, true);
166074
+ return text2({ error: "Knowledge Workspace is not initialized. Run workspace_init first." }, true);
165428
166075
  }
165429
166076
  const claims = new ClaimStore2();
165430
166077
  const workspaceStore = new KnowledgeWorkspaceStore2();
@@ -165432,7 +166079,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165432
166079
  if (action === "status") {
165433
166080
  const pages = workspaceStore.listPages(workspace.id);
165434
166081
  const pending = workspaceStore.listProposals(workspace.id, "pending");
165435
- return text({
166082
+ return text2({
165436
166083
  workspace: {
165437
166084
  id: workspace.id,
165438
166085
  mode: workspace.mode,
@@ -165450,7 +166097,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165450
166097
  });
165451
166098
  }
165452
166099
  if (action === "claim_list") {
165453
- return text({
166100
+ return text2({
165454
166101
  claims: claims.listClaims(project.id, { limit: 100 }).map((claim) => ({
165455
166102
  id: claim.id,
165456
166103
  subject: claim.subject,
@@ -165469,18 +166116,18 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165469
166116
  const requestedClaimId = requireText(claimId, "claimId");
165470
166117
  const detail = requireText(reviewDetail, "reviewDetail");
165471
166118
  if (!requestedClaimId || !claimReviewState || !detail) {
165472
- return text({ error: "claimId, claimReviewState, and reviewDetail are required for claim_review." }, true);
166119
+ return text2({ error: "claimId, claimReviewState, and reviewDetail are required for claim_review." }, true);
165473
166120
  }
165474
166121
  const existing = claims.getClaim(requestedClaimId);
165475
166122
  if (!existing || existing.projectId !== project.id) {
165476
- return text({ error: "Claim was not found for the current project." }, true);
166123
+ return text2({ error: "Claim was not found for the current project." }, true);
165477
166124
  }
165478
166125
  const claim = reviewClaim2(claims, {
165479
166126
  claimId: requestedClaimId,
165480
166127
  reviewState: claimReviewState,
165481
166128
  detail
165482
166129
  });
165483
- return text({
166130
+ return text2({
165484
166131
  claim: {
165485
166132
  id: claim.id,
165486
166133
  status: claim.status,
@@ -165492,7 +166139,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165492
166139
  }
165493
166140
  if (action === "compile") {
165494
166141
  const result = await compileKnowledgeWorkspace2({ workspace, claims });
165495
- return text({
166142
+ return text2({
165496
166143
  proposals: result.proposals.map((proposal) => ({
165497
166144
  id: proposal.id,
165498
166145
  targetPath: proposal.targetPath,
@@ -165507,17 +166154,17 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165507
166154
  const codeStore = new CodeGraphStore2();
165508
166155
  await codeStore.init(projectDir2);
165509
166156
  const result = await lintKnowledgeWorkspace2({ workspace, claims, codeStore });
165510
- return text(result);
166157
+ return text2(result);
165511
166158
  }
165512
166159
  if (action === "proposal_apply") {
165513
166160
  const proposal = requireText(proposalId, "proposalId");
165514
- if (!proposal) return text({ error: "proposalId is required for proposal_apply." }, true);
166161
+ if (!proposal) return text2({ error: "proposalId is required for proposal_apply." }, true);
165515
166162
  const result = await applyKnowledgeProposal2({
165516
166163
  workspace,
165517
166164
  proposalId: proposal,
165518
166165
  allowManualOverwrite: !!allowManualOverwrite
165519
166166
  });
165520
- return text({
166167
+ return text2({
165521
166168
  proposal: { id: result.proposal.id, status: result.proposal.status },
165522
166169
  targetPath: result.targetPath
165523
166170
  });
@@ -165527,7 +166174,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165527
166174
  const projectRoot = workspace.projectRoot ?? project.rootPath;
165528
166175
  if (action === "workflow_import") {
165529
166176
  const result = await importWindsurfWorkflows2({ workspace, projectRoot });
165530
- return text({
166177
+ return text2({
165531
166178
  imported: result.imported.map((workflow2) => ({
165532
166179
  id: workflow2.id,
165533
166180
  title: workflow2.title,
@@ -165540,7 +166187,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165540
166187
  }
165541
166188
  const synced = await syncCanonicalWorkflows2(workspace);
165542
166189
  if (action === "workflow_list") {
165543
- return text({
166190
+ return text2({
165544
166191
  workflows: workflowStore.listWorkflows(workspace.id).map((workflow2) => ({
165545
166192
  id: workflow2.id,
165546
166193
  title: workflow2.title,
@@ -165555,9 +166202,9 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165555
166202
  }
165556
166203
  if (action === "workflow_select") {
165557
166204
  const selectedTask = requireText(task, "task");
165558
- if (!selectedTask) return text({ error: "task is required for workflow_select." }, true);
166205
+ if (!selectedTask) return text2({ error: "task is required for workflow_select." }, true);
165559
166206
  const result = await selectWorkspaceWorkflows2({ workspace, task: selectedTask });
165560
- return text({
166207
+ return text2({
165561
166208
  selections: result.selections.map((selection) => ({
165562
166209
  id: selection.workflow.id,
165563
166210
  title: selection.workflow.title,
@@ -165569,16 +166216,16 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165569
166216
  });
165570
166217
  }
165571
166218
  const requestedWorkflowId = requireText(workflowId, "workflowId");
165572
- if (!requestedWorkflowId) return text({ error: "workflowId is required for this workflow action." }, true);
166219
+ if (!requestedWorkflowId) return text2({ error: "workflowId is required for this workflow action." }, true);
165573
166220
  const workflow = workflowStore.getWorkflow(requestedWorkflowId);
165574
166221
  if (!workflow || workflow.workspaceId !== workspace.id) {
165575
- return text({ error: "Workflow was not found for this Knowledge Workspace." }, true);
166222
+ return text2({ error: "Workflow was not found for this Knowledge Workspace." }, true);
165576
166223
  }
165577
166224
  if (action === "workflow_preview" || action === "workflow_apply") {
165578
166225
  const targetAgent = requireText(agent, "agent");
165579
- if (!targetAgent) return text({ error: "agent is required for a workflow adapter action." }, true);
166226
+ if (!targetAgent) return text2({ error: "agent is required for a workflow adapter action." }, true);
165580
166227
  const result = action === "workflow_preview" ? await previewWorkflowAdapter2({ workflow, projectRoot, agent: targetAgent }) : await applyWorkflowAdapter2({ workflow, projectRoot, agent: targetAgent });
165581
- return text({
166228
+ return text2({
165582
166229
  workflowId: workflow.id,
165583
166230
  agent: targetAgent,
165584
166231
  status: result.status,
@@ -165589,8 +166236,8 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165589
166236
  }
165590
166237
  if (action === "workflow_run") {
165591
166238
  const runTask = requireText(task, "task");
165592
- if (!runTask) return text({ error: "task is required for workflow_run." }, true);
165593
- if (!outcome) return text({ error: "outcome is required for workflow_run." }, true);
166239
+ if (!runTask) return text2({ error: "task is required for workflow_run." }, true);
166240
+ if (!outcome) return text2({ error: "outcome is required for workflow_run." }, true);
165594
166241
  const result = await recordWorkflowRun2({
165595
166242
  workspace,
165596
166243
  run: {
@@ -165604,14 +166251,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165604
166251
  selectedEvidence: [...new Set((evidenceIds ?? []).map((item) => item.trim()).filter(Boolean))]
165605
166252
  }
165606
166253
  });
165607
- return text({
166254
+ return text2({
165608
166255
  id: result.id,
165609
166256
  workflowId: result.workflowId,
165610
166257
  outcome: result.outcome,
165611
166258
  verificationVerdict: result.verificationVerdict
165612
166259
  });
165613
166260
  }
165614
- return text({ error: "Unsupported knowledge action." }, true);
166261
+ return text2({ error: "Unsupported knowledge action." }, true);
165615
166262
  }
165616
166263
  );
165617
166264
  server.registerTool(
@@ -167086,10 +167733,10 @@ Ensure the path points to a directory containing a .git folder (or a subdirector
167086
167733
  ];
167087
167734
  const allSkills = await loadMiniSkills2(projectDir2, project.id);
167088
167735
  const miniSkills = allSkills.filter((s2) => {
167089
- const text = `${s2.title}
167736
+ const text2 = `${s2.title}
167090
167737
  ${s2.sourceEntity}
167091
167738
  ${s2.instruction}`.toLowerCase();
167092
- return !SKILL_NOISE.some((p) => p.test(text));
167739
+ return !SKILL_NOISE.some((p) => p.test(text2));
167093
167740
  });
167094
167741
  if (miniSkills.length > 0) {
167095
167742
  const formatted = formatMiniSkillsForInjection2(miniSkills);
@@ -168580,7 +169227,7 @@ var init_serve_shared = __esm({
168580
169227
 
168581
169228
  // src/cli/version.ts
168582
169229
  function getCliVersion() {
168583
- return true ? "1.4.0" : pkg.version;
169230
+ return true ? "1.4.2" : pkg.version;
168584
169231
  }
168585
169232
  var init_version3 = __esm({
168586
169233
  "src/cli/version.ts"() {