memorix 1.4.1 → 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.
package/dist/sdk.js CHANGED
@@ -363,7 +363,7 @@ function closeAllDatabases() {
363
363
  _dbCache.delete(key);
364
364
  }
365
365
  }
366
- var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
366
+ var BetterSqlite3, CREATE_OBSERVATIONS_TABLE, CREATE_MINI_SKILLS_TABLE, CREATE_SESSIONS_TABLE, CREATE_META_TABLE, CREATE_TEAM_AGENTS_TABLE, CREATE_TEAM_MESSAGES_TABLE, CREATE_TEAM_TASKS_TABLE, CREATE_TEAM_TASK_DEPS_TABLE, CREATE_TEAM_LOCKS_TABLE, CREATE_TEAM_ROLES_TABLE, CREATE_CHAT_TRANSCRIPT_TABLE, CREATE_GRAPH_ENTITIES_TABLE, CREATE_GRAPH_RELATIONS_TABLE, CREATE_CODE_FILES_TABLE, CREATE_CODE_SYMBOLS_TABLE, CREATE_CODE_EDGES_TABLE, CREATE_OBSERVATION_CODE_REFS_TABLE, CREATE_SCHEMA_MIGRATIONS_TABLE, CREATE_CODE_STATE_SNAPSHOTS_TABLE, CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE, CREATE_KNOWLEDGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_CLAIM_EVIDENCE_TABLE, CREATE_KNOWLEDGE_CLAIM_EVENTS_TABLE, CREATE_KNOWLEDGE_WORKSPACES_TABLE, CREATE_KNOWLEDGE_PAGES_TABLE, CREATE_KNOWLEDGE_PAGE_CLAIMS_TABLE, CREATE_KNOWLEDGE_PAGE_LINKS_TABLE, CREATE_KNOWLEDGE_PROPOSALS_TABLE, CREATE_KNOWLEDGE_WORKFLOWS_TABLE, CREATE_KNOWLEDGE_WORKFLOW_RUNS_TABLE, CREATE_LONG_TERM_MEMORIES_TABLE, CREATE_LONG_TERM_MEMORY_EVIDENCE_TABLE, CREATE_LONG_TERM_MEMORY_EVENTS_TABLE, CREATE_MEMORY_OUTCOME_SIGNALS_TABLE, CREATE_MEDIA_ASSETS_TABLE, CREATE_MEDIA_ASSET_LINKS_TABLE, CREATE_MEDIA_DERIVATIONS_TABLE, CREATE_MEDIA_EMBEDDING_PROFILES_TABLE, CREATE_MEDIA_EMBEDDINGS_TABLE, CREATE_MEDIA_JOBS_TABLE, CREATE_MAINTENANCE_JOBS_TABLE, CREATE_MAINTENANCE_TARGETS_TABLE, CREATE_COMPACTION_CHECKPOINTS_TABLE, CREATE_INDEXES, SCHEMA_MIGRATIONS, _dbCache;
367
367
  var init_sqlite_db = __esm({
368
368
  "src/store/sqlite-db.ts"() {
369
369
  "use strict";
@@ -629,6 +629,17 @@ CREATE TABLE IF NOT EXISTS observation_code_refs (
629
629
  " UNIQUE(projectId, sourceEpoch)",
630
630
  ");"
631
631
  ].join("\n");
632
+ CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE = [
633
+ "CREATE TABLE IF NOT EXISTS code_state_snapshot_files (",
634
+ " snapshotId TEXT NOT NULL,",
635
+ " projectId TEXT NOT NULL,",
636
+ " fileId TEXT NOT NULL,",
637
+ " path TEXT NOT NULL,",
638
+ " contentHash TEXT NOT NULL,",
639
+ " PRIMARY KEY (snapshotId, path),",
640
+ " FOREIGN KEY (snapshotId) REFERENCES code_state_snapshots(id) ON DELETE CASCADE",
641
+ ");"
642
+ ].join("\n");
632
643
  CREATE_KNOWLEDGE_CLAIMS_TABLE = `
633
644
  CREATE TABLE IF NOT EXISTS knowledge_claims (
634
645
  id TEXT PRIMARY KEY,
@@ -839,6 +850,19 @@ CREATE TABLE IF NOT EXISTS long_term_memory_events (
839
850
  createdAt TEXT NOT NULL,
840
851
  FOREIGN KEY (memoryId) REFERENCES long_term_memories(id) ON DELETE CASCADE
841
852
  );
853
+ `;
854
+ CREATE_MEMORY_OUTCOME_SIGNALS_TABLE = `
855
+ CREATE TABLE IF NOT EXISTS memory_outcome_signals (
856
+ id TEXT PRIMARY KEY,
857
+ projectId TEXT NOT NULL,
858
+ candidateKind TEXT NOT NULL,
859
+ candidateId TEXT NOT NULL,
860
+ kind TEXT NOT NULL,
861
+ sourceRef TEXT NOT NULL,
862
+ snapshotId TEXT,
863
+ detail TEXT,
864
+ observedAt TEXT NOT NULL
865
+ );
842
866
  `;
843
867
  CREATE_MEDIA_ASSETS_TABLE = `
844
868
  CREATE TABLE IF NOT EXISTS media_assets (
@@ -1081,6 +1105,20 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
1081
1105
  db2.exec("CREATE INDEX IF NOT EXISTS idx_code_edges_snapshot ON code_edges(projectId, snapshotId)");
1082
1106
  }
1083
1107
  },
1108
+ {
1109
+ id: "1.4-codegraph-snapshot-manifest",
1110
+ apply: (db2) => {
1111
+ db2.exec(CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE);
1112
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_code_snapshot_files_project_path ON code_state_snapshot_files(projectId, path)");
1113
+ }
1114
+ },
1115
+ {
1116
+ id: "1.4-memory-outcome-signals",
1117
+ apply: (db2) => {
1118
+ db2.exec(CREATE_MEMORY_OUTCOME_SIGNALS_TABLE);
1119
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_outcomes_candidate ON memory_outcome_signals(projectId, candidateKind, candidateId, observedAt DESC)");
1120
+ }
1121
+ },
1084
1122
  {
1085
1123
  id: "1.2-knowledge-claim-ledger",
1086
1124
  apply: (db2) => {
@@ -2280,17 +2318,17 @@ var init_mini_skill_store = __esm({
2280
2318
 
2281
2319
  // src/compact/token-budget.ts
2282
2320
  import { countTokens, isWithinTokenLimit } from "gpt-tokenizer";
2283
- function countTextTokens(text) {
2284
- return countTokens(text);
2321
+ function countTextTokens(text2) {
2322
+ return countTokens(text2);
2285
2323
  }
2286
- function fitsInBudget(text, limit2) {
2287
- return isWithinTokenLimit(text, limit2);
2324
+ function fitsInBudget(text2, limit2) {
2325
+ return isWithinTokenLimit(text2, limit2);
2288
2326
  }
2289
- function truncateToTokenBudget(text, budget) {
2290
- if (fitsInBudget(text, budget) !== false) {
2291
- return text;
2327
+ function truncateToTokenBudget(text2, budget) {
2328
+ if (fitsInBudget(text2, budget) !== false) {
2329
+ return text2;
2292
2330
  }
2293
- const sentences = text.split(/(?<=[.!?])\s+/);
2331
+ const sentences = text2.split(/(?<=[.!?])\s+/);
2294
2332
  let result = "";
2295
2333
  for (const sentence of sentences) {
2296
2334
  const candidate = result ? `${result} ${sentence}` : sentence;
@@ -2301,12 +2339,12 @@ function truncateToTokenBudget(text, budget) {
2301
2339
  }
2302
2340
  if (!result) {
2303
2341
  const estimatedChars = budget * 2;
2304
- result = text.slice(0, estimatedChars);
2342
+ result = text2.slice(0, estimatedChars);
2305
2343
  while (fitsInBudget(result, budget) === false && result.length > 0) {
2306
2344
  result = result.slice(0, Math.floor(result.length * 0.9));
2307
2345
  }
2308
- if (result.length < text.length) {
2309
- const nextCharacter = text.charAt(result.length);
2346
+ if (result.length < text2.length) {
2347
+ const nextCharacter = text2.charAt(result.length);
2310
2348
  if (nextCharacter && !/[\s.,;:!?)}\]]/.test(nextCharacter)) {
2311
2349
  const boundary = result.search(/\s+\S*$/);
2312
2350
  result = boundary > 0 ? result.slice(0, boundary).trimEnd() : "";
@@ -3438,8 +3476,8 @@ import { createHash } from "crypto";
3438
3476
  import { readFile, writeFile, mkdir } from "fs/promises";
3439
3477
  import { join as join2 } from "path";
3440
3478
  import { homedir as homedir6 } from "os";
3441
- function textHash(text) {
3442
- return createHash("sha256").update(text).digest("hex").slice(0, 16);
3479
+ function textHash(text2) {
3480
+ return createHash("sha256").update(text2).digest("hex").slice(0, 16);
3443
3481
  }
3444
3482
  async function loadDiskCache() {
3445
3483
  try {
@@ -3502,11 +3540,11 @@ var init_fastembed_provider = __esm({
3502
3540
  async embedInputs(inputs, options = {}) {
3503
3541
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
3504
3542
  }
3505
- async embed(text) {
3506
- const hash4 = textHash(text);
3543
+ async embed(text2) {
3544
+ const hash4 = textHash(text2);
3507
3545
  const cached = cache.get(hash4);
3508
3546
  if (cached) return cached;
3509
- const raw = await this.model.queryEmbed(text);
3547
+ const raw = await this.model.queryEmbed(text2);
3510
3548
  const result = Array.from(raw);
3511
3549
  if (result.length !== this.dimensions) {
3512
3550
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
@@ -3602,10 +3640,10 @@ var init_transformers_provider = __esm({
3602
3640
  async embedInputs(inputs, options = {}) {
3603
3641
  return Promise.all(inputs.map((input) => this.embedInput(input, options)));
3604
3642
  }
3605
- async embed(text) {
3606
- const cached = cache2.get(text);
3643
+ async embed(text2) {
3644
+ const cached = cache2.get(text2);
3607
3645
  if (cached) return cached;
3608
- const output = await this.extractor(text, {
3646
+ const output = await this.extractor(text2, {
3609
3647
  pooling: "mean",
3610
3648
  normalize: true
3611
3649
  });
@@ -3613,7 +3651,7 @@ var init_transformers_provider = __esm({
3613
3651
  if (result.length !== this.dimensions) {
3614
3652
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
3615
3653
  }
3616
- this.cacheSet(text, result);
3654
+ this.cacheSet(text2, result);
3617
3655
  return result;
3618
3656
  }
3619
3657
  async embedBatch(texts) {
@@ -3676,8 +3714,8 @@ function dimsCacheFile() {
3676
3714
  function cacheMetaFile() {
3677
3715
  return join3(cacheDir(), ".embedding-api-cache-meta.json");
3678
3716
  }
3679
- function normalizeText(text) {
3680
- return text.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
3717
+ function normalizeText(text2) {
3718
+ return text2.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
3681
3719
  }
3682
3720
  function cacheNamespace(config) {
3683
3721
  return [
@@ -3687,8 +3725,8 @@ function cacheNamespace(config) {
3687
3725
  config.requestedDimensions ?? "native"
3688
3726
  ].join("|");
3689
3727
  }
3690
- function textHash2(text, namespace) {
3691
- return createHash2("sha256").update(`${namespace}\0${text}`).digest("hex").slice(0, 16);
3728
+ function textHash2(text2, namespace) {
3729
+ return createHash2("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
3692
3730
  }
3693
3731
  function inputIdentity(input, options = {}) {
3694
3732
  return JSON.stringify({
@@ -4100,8 +4138,8 @@ var init_api_provider = __esm({
4100
4138
  if (!embedding) throw new Error("API probe returned no embeddings; check model name and API key");
4101
4139
  return embedding.length;
4102
4140
  }
4103
- async embed(text, options) {
4104
- const normalized = normalizeText(text);
4141
+ async embed(text2, options) {
4142
+ const normalized = normalizeText(text2);
4105
4143
  if (isNativeGeminiEndpoint(this.config.baseUrl)) {
4106
4144
  return this.embedInput({ modality: "text", text: normalized }, { intent: "document", ...options });
4107
4145
  }
@@ -4158,7 +4196,7 @@ var init_api_provider = __esm({
4158
4196
  }
4159
4197
  async embedBatch(texts, options) {
4160
4198
  if (isNativeGeminiEndpoint(this.config.baseUrl)) {
4161
- return Promise.all(texts.map((text) => this.embedInput({ modality: "text", text }, { intent: "document", ...options })));
4199
+ return Promise.all(texts.map((text2) => this.embedInput({ modality: "text", text: text2 }, { intent: "document", ...options })));
4162
4200
  }
4163
4201
  await ensureDiskCacheLoaded();
4164
4202
  const normalizedTexts = texts.map(normalizeText);
@@ -4237,8 +4275,8 @@ var init_api_provider = __esm({
4237
4275
  }
4238
4276
  async getCachedEmbeddings(texts) {
4239
4277
  await ensureDiskCacheLoaded();
4240
- return texts.map((text) => {
4241
- const hash4 = textHash2(normalizeText(text), this.cacheKeyNamespace);
4278
+ return texts.map((text2) => {
4279
+ const hash4 = textHash2(normalizeText(text2), this.cacheKeyNamespace);
4242
4280
  return cache3.get(hash4) ?? null;
4243
4281
  });
4244
4282
  }
@@ -4468,9 +4506,9 @@ function wrapProvider(candidate) {
4468
4506
  return {
4469
4507
  name: candidate.name,
4470
4508
  dimensions: candidate.dimensions,
4471
- async embed(text, options) {
4509
+ async embed(text2, options) {
4472
4510
  try {
4473
- return await candidate.embed(text, options);
4511
+ return await candidate.embed(text2, options);
4474
4512
  } catch (error) {
4475
4513
  if (kind === "api" && getEmbeddingMode2() === "auto" && isTemporaryEmbeddingFailure(error)) {
4476
4514
  warnOnce("[memorix] API embedding temporarily unavailable \u2014 switching to local fallback provider");
@@ -4478,7 +4516,7 @@ function wrapProvider(candidate) {
4478
4516
  if (fallback) {
4479
4517
  provider = wrapProvider(fallback);
4480
4518
  warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);
4481
- return provider.embed(text, options);
4519
+ return provider.embed(text2, options);
4482
4520
  }
4483
4521
  }
4484
4522
  if (isTemporaryEmbeddingFailure(error)) {
@@ -5037,8 +5075,8 @@ async function readResponseText(response, signal, maxBytes = MAX_LLM_RESPONSE_BY
5037
5075
  }
5038
5076
  }
5039
5077
  async function readResponseJson(response, signal, maxBytes = MAX_LLM_RESPONSE_BYTES) {
5040
- const text = await readResponseText(response, signal, maxBytes);
5041
- return JSON.parse(text);
5078
+ const text2 = await readResponseText(response, signal, maxBytes);
5079
+ return JSON.parse(text2);
5042
5080
  }
5043
5081
  async function* callLLMWithToolsStream(messages, tools) {
5044
5082
  if (!currentConfig) {
@@ -5591,8 +5629,8 @@ function isCjkHeavy(query) {
5591
5629
  const cjkCount = (query.match(CJK_PATTERN) || []).length;
5592
5630
  return query.length > 0 && cjkCount / query.length > 0.3;
5593
5631
  }
5594
- function normalizeExpansion(text) {
5595
- return text.trim().replace(/^[-*]\s*/, "").replace(/^["'`]+|["'`]+$/g, "").split(/\r?\n/)[0].trim();
5632
+ function normalizeExpansion(text2) {
5633
+ return text2.trim().replace(/^[-*]\s*/, "").replace(/^["'`]+|["'`]+$/g, "").split(/\r?\n/)[0].trim();
5596
5634
  }
5597
5635
  async function maybeExpandSearchQuery(query) {
5598
5636
  if (!query || !isCjkHeavy(query) || COMMAND_LIKE_QUERY.test(query)) {
@@ -5955,9 +5993,9 @@ function shouldSkipCompression(narrative, type) {
5955
5993
  if (specialChars / narrative.length > 0.35) return true;
5956
5994
  return false;
5957
5995
  }
5958
- function estimateTokens(text) {
5959
- const cjkChars = (text.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length;
5960
- const otherChars = text.length - cjkChars;
5996
+ function estimateTokens(text2) {
5997
+ const cjkChars = (text2.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length;
5998
+ const otherChars = text2.length - cjkChars;
5961
5999
  return Math.ceil(cjkChars / 1.5 + otherChars / 4);
5962
6000
  }
5963
6001
  var COMPRESS_PROMPT, COMPRESS_PROMPT_GENTLE, RERANK_PROMPT, SKIP_PATTERNS, LOW_COMPRESSION_TYPES;
@@ -6260,10 +6298,10 @@ function isEmbeddingEnabled() {
6260
6298
  function getVectorDimensions() {
6261
6299
  return embeddingEnabled ? embeddingDimensions : null;
6262
6300
  }
6263
- async function generateEmbedding(text) {
6301
+ async function generateEmbedding(text2) {
6264
6302
  const provider2 = await getEmbeddingProvider();
6265
6303
  if (!provider2) return null;
6266
- return provider2.embedInput ? provider2.embedInput({ modality: "text", text }, { intent: "document" }) : provider2.embed(text);
6304
+ return provider2.embedInput ? provider2.embedInput({ modality: "text", text: text2 }, { intent: "document" }) : provider2.embed(text2);
6267
6305
  }
6268
6306
  async function generateEmbeddingInput(input, options = {}) {
6269
6307
  const provider2 = await getEmbeddingProvider();
@@ -7595,9 +7633,9 @@ var init_entity_extractor = __esm({
7595
7633
  });
7596
7634
 
7597
7635
  // src/memory/secret-filter.ts
7598
- function applyRedaction(text) {
7599
- if (!text) return text;
7600
- let out = text;
7636
+ function applyRedaction(text2) {
7637
+ if (!text2) return text2;
7638
+ let out = text2;
7601
7639
  out = out.replace(
7602
7640
  /((?:password|passwd|pwd|secret|token|api[_-]?key|auth[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret)\s*[:=]\s*["']?)([^\s"',;\n]{6,})/gi,
7603
7641
  "$1[REDACTED]"
@@ -7611,11 +7649,11 @@ function applyRedaction(text) {
7611
7649
  out = out.replace(/\beyJ[A-Za-z0-9._-]{40,}\b/g, "[REDACTED]");
7612
7650
  return out;
7613
7651
  }
7614
- function sanitizeCredentials(text) {
7615
- return applyRedaction(text);
7652
+ function sanitizeCredentials(text2) {
7653
+ return applyRedaction(text2);
7616
7654
  }
7617
- function redactCredentials(text) {
7618
- return applyRedaction(text);
7655
+ function redactCredentials(text2) {
7656
+ return applyRedaction(text2);
7619
7657
  }
7620
7658
  var init_secret_filter = __esm({
7621
7659
  "src/memory/secret-filter.ts"() {
@@ -7666,8 +7704,8 @@ function clampPositiveInteger(value, fallback) {
7666
7704
  return Math.max(1, Math.floor(value));
7667
7705
  }
7668
7706
  function errorText(error) {
7669
- const text = error instanceof Error ? error.message : String(error);
7670
- return sanitizeCredentials(text).slice(0, MAX_ERROR_LENGTH);
7707
+ const text2 = error instanceof Error ? error.message : String(error);
7708
+ return sanitizeCredentials(text2).slice(0, MAX_ERROR_LENGTH);
7671
7709
  }
7672
7710
  function normalizedKinds(kinds) {
7673
7711
  if (!kinds) return void 0;
@@ -8761,9 +8799,9 @@ __export(consolidation_exports, {
8761
8799
  executeConsolidation: () => executeConsolidation,
8762
8800
  findConsolidationCandidates: () => findConsolidationCandidates
8763
8801
  });
8764
- function tokenize(text) {
8802
+ function tokenize(text2) {
8765
8803
  return new Set(
8766
- text.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff\s-]/g, " ").split(/\s+/).filter((t2) => t2.length > 1)
8804
+ text2.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff\s-]/g, " ").split(/\s+/).filter((t2) => t2.length > 1)
8767
8805
  );
8768
8806
  }
8769
8807
  function jaccardSimilarity(a, b) {
@@ -17915,8 +17953,8 @@ var init_headers = __esm({
17915
17953
  });
17916
17954
 
17917
17955
  // packages/ai/dist/utils/sanitize-unicode.js
17918
- function sanitizeSurrogates(text) {
17919
- return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
17956
+ function sanitizeSurrogates(text2) {
17957
+ return text2.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
17920
17958
  }
17921
17959
  var init_sanitize_unicode = __esm({
17922
17960
  "packages/ai/dist/utils/sanitize-unicode.js"() {
@@ -18398,9 +18436,9 @@ var init_values = __esm({
18398
18436
  }
18399
18437
  return n;
18400
18438
  };
18401
- safeJSON = (text) => {
18439
+ safeJSON = (text2) => {
18402
18440
  try {
18403
- return JSON.parse(text);
18441
+ return JSON.parse(text2);
18404
18442
  } catch (err) {
18405
18443
  return void 0;
18406
18444
  }
@@ -19563,8 +19601,8 @@ async function defaultParseResponse(client, props) {
19563
19601
  const json2 = await response.json();
19564
19602
  return addRequestID(json2, response);
19565
19603
  }
19566
- const text = await response.text();
19567
- return text;
19604
+ const text2 = await response.text();
19605
+ return text2;
19568
19606
  })();
19569
19607
  loggerFor(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails({
19570
19608
  retryOfRequestLogID,
@@ -45182,9 +45220,9 @@ var init_values2 = __esm({
45182
45220
  }
45183
45221
  return n;
45184
45222
  };
45185
- safeJSON2 = (text) => {
45223
+ safeJSON2 = (text2) => {
45186
45224
  try {
45187
- return JSON.parse(text);
45225
+ return JSON.parse(text2);
45188
45226
  } catch (err) {
45189
45227
  return void 0;
45190
45228
  }
@@ -45958,8 +45996,8 @@ async function defaultParseResponse2(client, props) {
45958
45996
  const json2 = await response.json();
45959
45997
  return addRequestID2(json2, response);
45960
45998
  }
45961
- const text = await response.text();
45962
- return text;
45999
+ const text2 = await response.text();
46000
+ return text2;
45963
46001
  })();
45964
46002
  loggerFor2(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails2({
45965
46003
  retryOfRequestLogID,
@@ -52552,9 +52590,9 @@ function decodeSseLine(line, state) {
52552
52590
  }
52553
52591
  return null;
52554
52592
  }
52555
- function nextLineBreakIndex(text) {
52556
- const carriageReturnIndex = text.indexOf("\r");
52557
- const newlineIndex = text.indexOf("\n");
52593
+ function nextLineBreakIndex(text2) {
52594
+ const carriageReturnIndex = text2.indexOf("\r");
52595
+ const newlineIndex = text2.indexOf("\n");
52558
52596
  if (carriageReturnIndex === -1) {
52559
52597
  return newlineIndex;
52560
52598
  }
@@ -52563,18 +52601,18 @@ function nextLineBreakIndex(text) {
52563
52601
  }
52564
52602
  return Math.min(carriageReturnIndex, newlineIndex);
52565
52603
  }
52566
- function consumeLine(text) {
52567
- const lineBreakIndex = nextLineBreakIndex(text);
52604
+ function consumeLine(text2) {
52605
+ const lineBreakIndex = nextLineBreakIndex(text2);
52568
52606
  if (lineBreakIndex === -1) {
52569
52607
  return null;
52570
52608
  }
52571
52609
  let nextIndex = lineBreakIndex + 1;
52572
- if (text[lineBreakIndex] === "\r" && text[nextIndex] === "\n") {
52610
+ if (text2[lineBreakIndex] === "\r" && text2[nextIndex] === "\n") {
52573
52611
  nextIndex += 1;
52574
52612
  }
52575
52613
  return {
52576
- line: text.slice(0, lineBreakIndex),
52577
- rest: text.slice(nextIndex)
52614
+ line: text2.slice(0, lineBreakIndex),
52615
+ rest: text2.slice(nextIndex)
52578
52616
  };
52579
52617
  }
52580
52618
  async function* iterateSseMessages(body, signal) {
@@ -54741,8 +54779,8 @@ var require_common = __commonJS({
54741
54779
  }
54742
54780
  function redactString(obj, key) {
54743
54781
  if (typeof obj === "object" && obj !== null && typeof obj[key] === "string") {
54744
- const text = obj[key];
54745
- if (/grant_type=/i.test(text) || /assertion=/i.test(text) || /secret/i.test(text)) {
54782
+ const text2 = obj[key];
54783
+ if (/grant_type=/i.test(text2) || /assertion=/i.test(text2) || /secret/i.test(text2)) {
54746
54784
  obj[key] = REDACT;
54747
54785
  }
54748
54786
  }
@@ -61570,8 +61608,8 @@ var init_body = __esm({
61570
61608
  * @return Promise
61571
61609
  */
61572
61610
  async json() {
61573
- const text = await this.text();
61574
- return JSON.parse(text);
61611
+ const text2 = await this.text();
61612
+ return JSON.parse(text2);
61575
61613
  }
61576
61614
  /**
61577
61615
  * Decode response as text
@@ -62723,7 +62761,7 @@ var require_gaxios = __commonJS({
62723
62761
  var retry_js_1 = require_retry3();
62724
62762
  var stream_1 = __require("stream");
62725
62763
  var interceptor_js_1 = require_interceptor();
62726
- var randomUUID16 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
62764
+ var randomUUID17 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
62727
62765
  var HTTP_STATUS_NO_CONTENT = 204;
62728
62766
  var Gaxios = class {
62729
62767
  agentCache = /* @__PURE__ */ new Map();
@@ -62996,7 +63034,7 @@ var require_gaxios = __commonJS({
62996
63034
  */
62997
63035
  ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
62998
63036
  if (opts.multipart?.length) {
62999
- const boundary = await randomUUID16();
63037
+ const boundary = await randomUUID17();
63000
63038
  preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
63001
63039
  opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
63002
63040
  } else if (shouldDirectlyPassData) {
@@ -64747,18 +64785,18 @@ var require_parse = __commonJS({
64747
64785
  n: "\n",
64748
64786
  r: "\r",
64749
64787
  t: " "
64750
- }, text, error = function(m2) {
64788
+ }, text2, error = function(m2) {
64751
64789
  throw {
64752
64790
  name: "SyntaxError",
64753
64791
  message: m2,
64754
64792
  at,
64755
- text
64793
+ text: text2
64756
64794
  };
64757
64795
  }, next = function(c) {
64758
64796
  if (c && c !== ch) {
64759
64797
  error("Expected '" + c + "' instead of '" + ch + "'");
64760
64798
  }
64761
- ch = text.charAt(at);
64799
+ ch = text2.charAt(at);
64762
64800
  at += 1;
64763
64801
  return ch;
64764
64802
  }, number44 = function() {
@@ -64805,12 +64843,12 @@ var require_parse = __commonJS({
64805
64843
  var startAt = at;
64806
64844
  while (next()) {
64807
64845
  if (ch === '"') {
64808
- if (at - 1 > startAt) string474 += text.substring(startAt, at - 1);
64846
+ if (at - 1 > startAt) string474 += text2.substring(startAt, at - 1);
64809
64847
  next();
64810
64848
  return string474;
64811
64849
  }
64812
64850
  if (ch === "\\") {
64813
- if (at - 1 > startAt) string474 += text.substring(startAt, at - 1);
64851
+ if (at - 1 > startAt) string474 += text2.substring(startAt, at - 1);
64814
64852
  next();
64815
64853
  if (ch === "u") {
64816
64854
  uffff = 0;
@@ -64943,7 +64981,7 @@ var require_parse = __commonJS({
64943
64981
  };
64944
64982
  return function(source, reviver) {
64945
64983
  var result;
64946
- text = source + "";
64984
+ text2 = source + "";
64947
64985
  at = 0;
64948
64986
  ch = " ";
64949
64987
  result = value();
@@ -65855,8 +65893,8 @@ var require_crypto = __commonJS({
65855
65893
  const result = new TextDecoder().decode(uint8array);
65856
65894
  return result;
65857
65895
  }
65858
- encodeBase64StringUtf8(text) {
65859
- const uint8array = new TextEncoder().encode(text);
65896
+ encodeBase64StringUtf8(text2) {
65897
+ const uint8array = new TextEncoder().encode(text2);
65860
65898
  const result = base64js.fromByteArray(uint8array);
65861
65899
  return result;
65862
65900
  }
@@ -65925,8 +65963,8 @@ var require_crypto2 = __commonJS({
65925
65963
  decodeBase64StringUtf8(base64) {
65926
65964
  return Buffer.from(base64, "base64").toString("utf-8");
65927
65965
  }
65928
- encodeBase64StringUtf8(text) {
65929
- return Buffer.from(text, "utf-8").toString("base64");
65966
+ encodeBase64StringUtf8(text2) {
65967
+ return Buffer.from(text2, "utf-8").toString("base64");
65930
65968
  }
65931
65969
  /**
65932
65970
  * Computes the SHA-256 hash of the provided string.
@@ -86371,8 +86409,8 @@ async function defaultParseResponse3(client, props) {
86371
86409
  const json2 = await response.json();
86372
86410
  return json2;
86373
86411
  }
86374
- const text = await response.text();
86375
- return text;
86412
+ const text2 = await response.text();
86413
+ return text2;
86376
86414
  })();
86377
86415
  loggerFor3(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails3({
86378
86416
  retryOfRequestLogID,
@@ -87949,7 +87987,7 @@ var init_node = __esm({
87949
87987
  if (this.candidates && this.candidates.length > 1) {
87950
87988
  console.warn("there are multiple candidates in the response, returning text from the first one.");
87951
87989
  }
87952
- let text = "";
87990
+ let text2 = "";
87953
87991
  let anyTextPartText = false;
87954
87992
  const nonTextParts = [];
87955
87993
  for (const part of (_h = (_g = (_f = (_e = this.candidates) === null || _e === void 0 ? void 0 : _e[0]) === null || _f === void 0 ? void 0 : _f.content) === null || _g === void 0 ? void 0 : _g.parts) !== null && _h !== void 0 ? _h : []) {
@@ -87963,13 +88001,13 @@ var init_node = __esm({
87963
88001
  continue;
87964
88002
  }
87965
88003
  anyTextPartText = true;
87966
- text += part.text;
88004
+ text2 += part.text;
87967
88005
  }
87968
88006
  }
87969
88007
  if (nonTextParts.length > 0) {
87970
88008
  console.warn(`there are non-text parts ${nonTextParts} in the response, returning concatenation of all text parts. Please refer to the non text parts for a full response from model.`);
87971
88009
  }
87972
- return anyTextPartText ? text : void 0;
88010
+ return anyTextPartText ? text2 : void 0;
87973
88011
  }
87974
88012
  /**
87975
88013
  * Returns the concatenation of all inline data parts from the first candidate
@@ -88222,7 +88260,7 @@ var init_node = __esm({
88222
88260
  */
88223
88261
  get text() {
88224
88262
  var _a5, _b, _c;
88225
- let text = "";
88263
+ let text2 = "";
88226
88264
  let anyTextPartFound = false;
88227
88265
  const nonTextParts = [];
88228
88266
  for (const part of (_c = (_b = (_a5 = this.serverContent) === null || _a5 === void 0 ? void 0 : _a5.modelTurn) === null || _b === void 0 ? void 0 : _b.parts) !== null && _c !== void 0 ? _c : []) {
@@ -88236,13 +88274,13 @@ var init_node = __esm({
88236
88274
  continue;
88237
88275
  }
88238
88276
  anyTextPartFound = true;
88239
- text += part.text;
88277
+ text2 += part.text;
88240
88278
  }
88241
88279
  }
88242
88280
  if (nonTextParts.length > 0) {
88243
88281
  console.warn(`there are non-text parts ${nonTextParts} in the response, returning concatenation of all text parts. Please refer to the non text parts for a full response from model.`);
88244
88282
  }
88245
- return anyTextPartFound ? text : void 0;
88283
+ return anyTextPartFound ? text2 : void 0;
88246
88284
  }
88247
88285
  /**
88248
88286
  * Returns the concatenation of all inline data parts from the server content if present.
@@ -92914,9 +92952,9 @@ var init_node = __esm({
92914
92952
  }
92915
92953
  return n;
92916
92954
  };
92917
- safeJSON3 = (text) => {
92955
+ safeJSON3 = (text2) => {
92918
92956
  try {
92919
- return JSON.parse(text);
92957
+ return JSON.parse(text2);
92920
92958
  } catch (err) {
92921
92959
  return void 0;
92922
92960
  }
@@ -110779,8 +110817,8 @@ function findBoundary(buf) {
110779
110817
  return null;
110780
110818
  }
110781
110819
  function parseMessage2(chunk, parse2, state, dataRequired) {
110782
- const text = new TextDecoder().decode(chunk);
110783
- const lines = text.split(/\r\n|\r|\n/);
110820
+ const text2 = new TextDecoder().decode(chunk);
110821
+ const lines = text2.split(/\r\n|\r|\n/);
110784
110822
  const dataLines = [];
110785
110823
  const ret = {};
110786
110824
  let ignore = true;
@@ -133654,10 +133692,10 @@ function formatMistralError(error) {
133654
133692
  }
133655
133693
  return safeJsonStringify(error);
133656
133694
  }
133657
- function truncateErrorText(text, maxChars) {
133658
- if (text.length <= maxChars)
133659
- return text;
133660
- return `${text.slice(0, maxChars)}... [truncated ${text.length - maxChars} chars]`;
133695
+ function truncateErrorText(text2, maxChars) {
133696
+ if (text2.length <= maxChars)
133697
+ return text2;
133698
+ return `${text2.slice(0, maxChars)}... [truncated ${text2.length - maxChars} chars]`;
133661
133699
  }
133662
133700
  function safeJsonStringify(value) {
133663
133701
  try {
@@ -133777,7 +133815,7 @@ async function consumeChatStream(model, output, stream2, mistralStream) {
133777
133815
  continue;
133778
133816
  }
133779
133817
  if (item.type === "thinking") {
133780
- const deltaText = item.thinking.map((part) => "text" in part ? part.text : "").filter((text) => text.length > 0).join("");
133818
+ const deltaText = item.thinking.map((part) => "text" in part ? part.text : "").filter((text2) => text2.length > 0).join("");
133781
133819
  const thinkingDelta = sanitizeSurrogates(deltaText);
133782
133820
  if (!thinkingDelta)
133783
133821
  continue;
@@ -133974,8 +134012,8 @@ function toChatMessages(messages, supportsImages) {
133974
134012
  }
133975
134013
  return result;
133976
134014
  }
133977
- function buildToolResultText(text, hasImages, supportsImages, isError) {
133978
- const trimmed = text.trim();
134015
+ function buildToolResultText(text2, hasImages, supportsImages, isError) {
134016
+ const trimmed = text2.trim();
133979
134017
  const errorPrefix = isError ? "[tool error] " : "";
133980
134018
  if (trimmed.length > 0) {
133981
134019
  const imageSuffix = hasImages && !supportsImages ? "\n[tool image omitted: model does not support images]" : "";
@@ -134776,14 +134814,14 @@ async function* parseWebSocket(socket, signal, idleTimeoutMs) {
134776
134814
  };
134777
134815
  const onMessage = (event) => {
134778
134816
  void (async () => {
134779
- let text = null;
134817
+ let text2 = null;
134780
134818
  try {
134781
134819
  if (!event || typeof event !== "object" || !("data" in event))
134782
134820
  return;
134783
- text = await decodeWebSocketData(event.data);
134784
- if (!text)
134821
+ text2 = await decodeWebSocketData(event.data);
134822
+ if (!text2)
134785
134823
  return;
134786
- const parsed = JSON.parse(text);
134824
+ const parsed = JSON.parse(text2);
134787
134825
  const type = typeof parsed.type === "string" ? parsed.type : "";
134788
134826
  if (type === "response.completed" || type === "response.done" || type === "response.incomplete") {
134789
134827
  sawCompletion = true;
@@ -134794,7 +134832,7 @@ async function* parseWebSocket(socket, signal, idleTimeoutMs) {
134794
134832
  } catch (cause) {
134795
134833
  failed = new CodexProtocolError(`Invalid Codex WebSocket JSON: ${formatThrownValue(cause)}`, {
134796
134834
  cause,
134797
- payload: text
134835
+ payload: text2
134798
134836
  });
134799
134837
  done = true;
134800
134838
  wake();
@@ -142987,11 +143025,11 @@ function videoRequestConfig(input) {
142987
143025
  };
142988
143026
  }
142989
143027
  async function readMiniMaxJson(response) {
142990
- const text = await response.text();
143028
+ const text2 = await response.text();
142991
143029
  let body = {};
142992
- if (text) {
143030
+ if (text2) {
142993
143031
  try {
142994
- const parsed = JSON.parse(text);
143032
+ const parsed = JSON.parse(text2);
142995
143033
  if (isRecord2(parsed)) body = parsed;
142996
143034
  } catch {
142997
143035
  throw new Error("MiniMax video API returned invalid JSON");
@@ -143894,6 +143932,7 @@ __export(store_exports, {
143894
143932
  CodeGraphStore: () => CodeGraphStore
143895
143933
  });
143896
143934
  import { randomUUID as randomUUID6 } from "crypto";
143935
+ import { posix as pathPosix } from "path";
143897
143936
  function rowToFile(row) {
143898
143937
  return {
143899
143938
  id: row.id,
@@ -143944,6 +143983,26 @@ function rowToEdge(row) {
143944
143983
  ...row.sourceEpoch != null ? { sourceEpoch: Number(row.sourceEpoch) } : {}
143945
143984
  };
143946
143985
  }
143986
+ function resolveRelativeImportTarget(sourcePath, evidence, fileByPath) {
143987
+ const target = evidence?.trim().replace(/\\/g, "/");
143988
+ if (!target?.startsWith(".")) return void 0;
143989
+ const base = normalizeCodePath(pathPosix.normalize(pathPosix.join(pathPosix.dirname(sourcePath), target)));
143990
+ if (!base || base === ".." || base.startsWith("../")) return void 0;
143991
+ const candidates = [base];
143992
+ const extensionMatch = base.match(/(\.[A-Za-z0-9]+)$/);
143993
+ const hasExtension = Boolean(extensionMatch);
143994
+ if (!hasExtension) {
143995
+ const extensions = [...new Set([...fileByPath.keys()].map((path33) => path33.match(/(\.[A-Za-z0-9]+)$/)?.[1]).filter((extension3) => Boolean(extension3)))];
143996
+ for (const extension3 of extensions) {
143997
+ candidates.push(`${base}${extension3}`, `${base}/index${extension3}`);
143998
+ }
143999
+ } else {
144000
+ const sourceStem = base.slice(0, -extensionMatch[1].length);
144001
+ const sourceExtensions = extensionMatch[1] === ".js" ? [".ts", ".tsx", ".js", ".jsx"] : extensionMatch[1] === ".mjs" ? [".mts", ".mjs"] : extensionMatch[1] === ".cjs" ? [".cts", ".cjs"] : [];
144002
+ for (const extension3 of sourceExtensions) candidates.push(`${sourceStem}${extension3}`);
144003
+ }
144004
+ return candidates.map((candidate) => fileByPath.get(candidate)).find((file) => Boolean(file));
144005
+ }
143947
144006
  function rowToRef(row) {
143948
144007
  return {
143949
144008
  id: row.id,
@@ -144004,6 +144063,18 @@ function rowToSnapshot(row) {
144004
144063
  ...row.previousSnapshotId ? { previousSnapshotId: row.previousSnapshotId } : {}
144005
144064
  };
144006
144065
  }
144066
+ function rowToSnapshotFile(row) {
144067
+ return {
144068
+ snapshotId: row.snapshotId,
144069
+ projectId: row.projectId,
144070
+ fileId: row.fileId,
144071
+ path: row.path,
144072
+ contentHash: row.contentHash
144073
+ };
144074
+ }
144075
+ function snapshotIsIncomplete(snapshot) {
144076
+ return snapshot.completeness.skippedOversizedFiles > 0 || (snapshot.completeness.unreadableFiles ?? 0) > 0 || snapshot.completeness.removalScanDeferred;
144077
+ }
144007
144078
  var CodeGraphStore;
144008
144079
  var init_store = __esm({
144009
144080
  "src/codegraph/store.ts"() {
@@ -144175,6 +144246,7 @@ var init_store = __esm({
144175
144246
  }
144176
144247
  });
144177
144248
  tx();
144249
+ this.reconcileLocalImportTargets(projectId);
144178
144250
  }
144179
144251
  /**
144180
144252
  * Reconcile only files whose source changed plus files that disappeared.
@@ -144184,7 +144256,10 @@ var init_store = __esm({
144184
144256
  const changed = input.changed.filter((delta) => delta.file.projectId === projectId);
144185
144257
  const metadataOnly = (input.metadataOnly ?? []).filter((file) => file.projectId === projectId);
144186
144258
  const removedFileIds = input.removedFileIds ?? [];
144187
- if (changed.length === 0 && metadataOnly.length === 0 && removedFileIds.length === 0) return;
144259
+ if (changed.length === 0 && metadataOnly.length === 0 && removedFileIds.length === 0) {
144260
+ this.reconcileLocalImportTargets(projectId);
144261
+ return;
144262
+ }
144188
144263
  const staleRefsForFile = this.db.prepare(`
144189
144264
  UPDATE observation_code_refs
144190
144265
  SET status = 'stale', updatedAt = ?
@@ -144194,9 +144269,18 @@ var init_store = __esm({
144194
144269
  )
144195
144270
  )
144196
144271
  `);
144197
- const deleteEdgesForFile = this.db.prepare(`
144272
+ const deleteEdgesFromFile = this.db.prepare(`
144273
+ DELETE FROM code_edges
144274
+ WHERE projectId = ? AND fromFileId = ?
144275
+ `);
144276
+ const clearImportTargetsForFile = this.db.prepare(`
144277
+ UPDATE code_edges
144278
+ SET toFileId = NULL
144279
+ WHERE projectId = ? AND toFileId = ? AND type = 'imports'
144280
+ `);
144281
+ const deleteOtherIncomingEdgesForFile = this.db.prepare(`
144198
144282
  DELETE FROM code_edges
144199
- WHERE projectId = ? AND (fromFileId = ? OR toFileId = ?)
144283
+ WHERE projectId = ? AND toFileId = ? AND type != 'imports'
144200
144284
  `);
144201
144285
  const deleteSymbolsForFile = this.db.prepare(`DELETE FROM code_symbols WHERE projectId = ? AND fileId = ?`);
144202
144286
  const deleteFile = this.db.prepare(`DELETE FROM code_files WHERE projectId = ? AND id = ?`);
@@ -144233,14 +144317,18 @@ var init_store = __esm({
144233
144317
  const staleAt = (/* @__PURE__ */ new Date()).toISOString();
144234
144318
  for (const fileId of removedFileIds) {
144235
144319
  staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);
144236
- deleteEdgesForFile.run(projectId, fileId, fileId);
144320
+ deleteEdgesFromFile.run(projectId, fileId);
144321
+ clearImportTargetsForFile.run(projectId, fileId);
144322
+ deleteOtherIncomingEdgesForFile.run(projectId, fileId);
144237
144323
  deleteSymbolsForFile.run(projectId, fileId);
144238
144324
  deleteFile.run(projectId, fileId);
144239
144325
  }
144240
144326
  for (const delta of changed) {
144241
144327
  const fileId = delta.file.id;
144242
144328
  staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);
144243
- deleteEdgesForFile.run(projectId, fileId, fileId);
144329
+ deleteEdgesFromFile.run(projectId, fileId);
144330
+ clearImportTargetsForFile.run(projectId, fileId);
144331
+ deleteOtherIncomingEdgesForFile.run(projectId, fileId);
144244
144332
  deleteSymbolsForFile.run(projectId, fileId);
144245
144333
  writeFile7(delta.file);
144246
144334
  for (const symbol of delta.symbols) {
@@ -144278,6 +144366,7 @@ var init_store = __esm({
144278
144366
  for (const file of metadataOnly) writeFile7(file);
144279
144367
  });
144280
144368
  tx();
144369
+ this.reconcileLocalImportTargets(projectId);
144281
144370
  }
144282
144371
  upsertObservationRefs(refs) {
144283
144372
  if (refs.length === 0) return;
@@ -144339,6 +144428,25 @@ var init_store = __esm({
144339
144428
  });
144340
144429
  tx();
144341
144430
  }
144431
+ /**
144432
+ * Lite import extraction records the original import text first. Resolve only
144433
+ * local relative imports against the current index after each refresh, so an
144434
+ * added or removed target cannot leave a fabricated file-to-file relation.
144435
+ */
144436
+ reconcileLocalImportTargets(projectId) {
144437
+ const fileById = new Map(this.listFiles(projectId).map((file) => [file.id, file]));
144438
+ const fileByPath = new Map([...fileById.values()].map((file) => [file.path, file]));
144439
+ const update2 = this.db.prepare("UPDATE code_edges SET toFileId = ? WHERE id = ?");
144440
+ const tx = this.db.transaction(() => {
144441
+ for (const edge of this.listEdges(projectId)) {
144442
+ if (edge.type !== "imports" || !edge.fromFileId) continue;
144443
+ const source = fileById.get(edge.fromFileId);
144444
+ const target = source ? resolveRelativeImportTarget(source.path, edge.evidence, fileByPath) : void 0;
144445
+ update2.run(target?.id ?? null, edge.id);
144446
+ }
144447
+ });
144448
+ tx();
144449
+ }
144342
144450
  getFile(projectId, path33) {
144343
144451
  const row = this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? AND path = ?`).get(projectId, normalizeCodePath(path33));
144344
144452
  return row ? rowToFile(row) : null;
@@ -144413,6 +144521,18 @@ var init_store = __esm({
144413
144521
  ORDER BY observationId, status, id
144414
144522
  `).all(projectId).map(rowToRef);
144415
144523
  }
144524
+ /** Count distinct observations whose binding to these exact files is stale. */
144525
+ countStaleObservationRefsForFiles(projectId, fileIds) {
144526
+ const ids = [...new Set(fileIds.filter(Boolean))];
144527
+ if (ids.length === 0) return 0;
144528
+ const placeholders = ids.map(() => "?").join(", ");
144529
+ const row = this.db.prepare(`
144530
+ SELECT COUNT(DISTINCT observationId) AS count
144531
+ FROM observation_code_refs
144532
+ WHERE projectId = ? AND status = 'stale' AND fileId IN (${placeholders})
144533
+ `).get(projectId, ...ids);
144534
+ return Number(row?.count ?? 0);
144535
+ }
144416
144536
  listReferencedSymbols(projectId) {
144417
144537
  return this.db.prepare(`
144418
144538
  SELECT DISTINCT symbols.*
@@ -144434,6 +144554,94 @@ var init_store = __esm({
144434
144554
  "SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT ?"
144435
144555
  ).all(projectId, safeLimit2).map(rowToSnapshot);
144436
144556
  }
144557
+ listSnapshotFiles(snapshotId) {
144558
+ return this.db.prepare(`
144559
+ SELECT snapshotId, projectId, fileId, path, contentHash
144560
+ FROM code_state_snapshot_files
144561
+ WHERE snapshotId = ?
144562
+ ORDER BY path
144563
+ `).all(snapshotId).map(rowToSnapshotFile);
144564
+ }
144565
+ diffSnapshots(projectId, fromSnapshotId, toSnapshotId) {
144566
+ const snapshots = this.db.prepare(`
144567
+ SELECT * FROM code_state_snapshots WHERE id IN (?, ?)
144568
+ `).all(fromSnapshotId, toSnapshotId).map(rowToSnapshot);
144569
+ if (snapshots.length !== 2) {
144570
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "missing-snapshot", changes: [] };
144571
+ }
144572
+ if (snapshots.some((snapshot) => snapshot.projectId !== projectId)) {
144573
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "project-mismatch", changes: [] };
144574
+ }
144575
+ if (snapshots.some(snapshotIsIncomplete)) {
144576
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "incomplete-snapshot", changes: [] };
144577
+ }
144578
+ const before = this.listSnapshotFiles(fromSnapshotId);
144579
+ const after = this.listSnapshotFiles(toSnapshotId);
144580
+ if (before.length === 0 || after.length === 0) {
144581
+ return {
144582
+ projectId,
144583
+ fromSnapshotId,
144584
+ toSnapshotId,
144585
+ available: false,
144586
+ reason: "legacy-snapshot-without-manifest",
144587
+ changes: []
144588
+ };
144589
+ }
144590
+ const beforeByPath = new Map(before.map((file) => [file.path, file]));
144591
+ const afterByPath = new Map(after.map((file) => [file.path, file]));
144592
+ const paths = [.../* @__PURE__ */ new Set([...beforeByPath.keys(), ...afterByPath.keys()])].sort();
144593
+ const changes = [];
144594
+ for (const path33 of paths) {
144595
+ const oldFile = beforeByPath.get(path33);
144596
+ const newFile = afterByPath.get(path33);
144597
+ if (!oldFile && newFile) {
144598
+ changes.push({ path: path33, kind: "added", afterHash: newFile.contentHash });
144599
+ } else if (oldFile && !newFile) {
144600
+ changes.push({ path: path33, kind: "removed", beforeHash: oldFile.contentHash });
144601
+ } else if (oldFile && newFile && oldFile.contentHash !== newFile.contentHash) {
144602
+ changes.push({ path: path33, kind: "modified", beforeHash: oldFile.contentHash, afterHash: newFile.contentHash });
144603
+ }
144604
+ }
144605
+ return { projectId, fromSnapshotId, toSnapshotId, available: true, changes };
144606
+ }
144607
+ impactSlice(projectId, changedPaths, maxRelations = 24) {
144608
+ const safeLimit2 = Number.isFinite(maxRelations) ? Math.max(1, Math.min(100, Math.floor(maxRelations))) : 24;
144609
+ const normalizedPaths = [...new Set(changedPaths.map(normalizeCodePath).filter(Boolean))].sort();
144610
+ const files = this.listFiles(projectId);
144611
+ const fileById = new Map(files.map((file) => [file.id, file.path]));
144612
+ const fileIdBySymbolId = new Map(this.listSymbols(projectId).map((symbol) => [symbol.id, symbol.fileId]));
144613
+ const changedIds = new Set(files.filter((file) => normalizedPaths.includes(file.path)).map((file) => file.id));
144614
+ const direct = /* @__PURE__ */ new Set();
144615
+ let relationCount = 0;
144616
+ let truncated = false;
144617
+ for (const edge of this.listEdges(projectId)) {
144618
+ const endpoints = [
144619
+ edge.fromFileId,
144620
+ edge.toFileId,
144621
+ edge.fromSymbolId ? fileIdBySymbolId.get(edge.fromSymbolId) : void 0,
144622
+ edge.toSymbolId ? fileIdBySymbolId.get(edge.toSymbolId) : void 0
144623
+ ].filter((id) => Boolean(id));
144624
+ if (!endpoints.some((id) => changedIds.has(id))) continue;
144625
+ const relatedPaths = endpoints.filter((id) => !changedIds.has(id)).map((id) => fileById.get(id)).filter((path33) => Boolean(path33));
144626
+ if (relatedPaths.length === 0) continue;
144627
+ if (relationCount >= safeLimit2) {
144628
+ truncated = true;
144629
+ break;
144630
+ }
144631
+ relationCount += 1;
144632
+ for (const path33 of relatedPaths) direct.add(path33);
144633
+ }
144634
+ const snapshot = this.latestSnapshot(projectId);
144635
+ return {
144636
+ projectId,
144637
+ ...snapshot ? { snapshotId: snapshot.id } : {},
144638
+ changedPaths: normalizedPaths,
144639
+ directlyConnectedPaths: [...direct].sort(),
144640
+ relationCount,
144641
+ truncated,
144642
+ provider: snapshot?.provider ?? "lite"
144643
+ };
144644
+ }
144437
144645
  /**
144438
144646
  * Record a completed scan and mark all current structural facts with its
144439
144647
  * epoch. The snapshot is written only after refresh reconciliation succeeds,
@@ -144475,6 +144683,16 @@ var init_store = __esm({
144475
144683
  this.db.prepare(
144476
144684
  "UPDATE observation_code_refs SET snapshotId = ? WHERE projectId = ? AND status = 'current'"
144477
144685
  ).run(id, input.projectId);
144686
+ const snapshotFileRows = this.db.prepare(`
144687
+ SELECT id, projectId, path, contentHash FROM code_files WHERE projectId = ? ORDER BY path
144688
+ `).all(input.projectId);
144689
+ const insertSnapshotFile = this.db.prepare(`
144690
+ INSERT INTO code_state_snapshot_files (snapshotId, projectId, fileId, path, contentHash)
144691
+ VALUES (?, ?, ?, ?, ?)
144692
+ `);
144693
+ for (const file of snapshotFileRows) {
144694
+ insertSnapshotFile.run(id, file.projectId, file.id, file.path, file.contentHash);
144695
+ }
144478
144696
  snapshot = {
144479
144697
  ...input,
144480
144698
  id,
@@ -144640,8 +144858,8 @@ __export(lite_provider_exports, {
144640
144858
  import { createHash as createHash7 } from "crypto";
144641
144859
  import { readdirSync as readdirSync2, readFileSync as readFileSync6, statSync as statSync3 } from "fs";
144642
144860
  import { join as join4, relative } from "path";
144643
- function hashText(text) {
144644
- return createHash7("sha256").update(text).digest("hex");
144861
+ function hashText(text2) {
144862
+ return createHash7("sha256").update(text2).digest("hex");
144645
144863
  }
144646
144864
  function extension2(path33) {
144647
144865
  const index = path33.lastIndexOf(".");
@@ -144685,19 +144903,19 @@ function walk(root, exclude, maxFiles) {
144685
144903
  visit(root);
144686
144904
  return out;
144687
144905
  }
144688
- function lineOf(text, index) {
144689
- return text.slice(0, index).split(/\r?\n/).length;
144906
+ function lineOf(text2, index) {
144907
+ return text2.slice(0, index).split(/\r?\n/).length;
144690
144908
  }
144691
- function extractSymbols(projectId, file, text, indexedAt) {
144909
+ function extractSymbols(projectId, file, text2, indexedAt) {
144692
144910
  const symbols = [];
144693
144911
  const profile = file.language ? languageProfiles[file.language] : void 0;
144694
144912
  const patterns = profile?.symbols ?? [];
144695
144913
  for (const { kind, re } of patterns) {
144696
144914
  re.lastIndex = 0;
144697
- for (const match2 of text.matchAll(re)) {
144915
+ for (const match2 of text2.matchAll(re)) {
144698
144916
  const name = match2[1];
144699
144917
  if (!name || name.includes("\n")) continue;
144700
- const startLine = lineOf(text, match2.index ?? 0);
144918
+ const startLine = lineOf(text2, match2.index ?? 0);
144701
144919
  const id = makeCodeSymbolId({ projectId, path: file.path, qualifiedName: name, kind });
144702
144920
  symbols.push({
144703
144921
  id,
@@ -144717,13 +144935,13 @@ function extractSymbols(projectId, file, text, indexedAt) {
144717
144935
  }
144718
144936
  return symbols;
144719
144937
  }
144720
- function extractImportEdges(projectId, file, text, indexedAt) {
144938
+ function extractImportEdges(projectId, file, text2, indexedAt) {
144721
144939
  const edges = [];
144722
144940
  const profile = file.language ? languageProfiles[file.language] : void 0;
144723
144941
  const imports = profile?.imports ?? [];
144724
144942
  for (const re of imports) {
144725
144943
  re.lastIndex = 0;
144726
- for (const match2 of text.matchAll(re)) {
144944
+ for (const match2 of text2.matchAll(re)) {
144727
144945
  const target = (match2[1] ?? "").trim();
144728
144946
  if (!target) continue;
144729
144947
  if (target.includes("\n")) {
@@ -144758,14 +144976,14 @@ function extractImportEdges(projectId, file, text, indexedAt) {
144758
144976
  function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
144759
144977
  const rel = normalizeCodePath(relative(projectRoot, abs));
144760
144978
  try {
144761
- const text = readFileSync6(abs, "utf-8");
144979
+ const text2 = readFileSync6(abs, "utf-8");
144762
144980
  const stat4 = fileStat ?? statSync3(abs);
144763
144981
  const file = {
144764
144982
  id: makeCodeFileId(projectId, rel),
144765
144983
  projectId,
144766
144984
  path: rel,
144767
144985
  language: languageForPath(rel),
144768
- contentHash: hashText(text),
144986
+ contentHash: hashText(text2),
144769
144987
  // Preserve filesystem precision. Rounding here made same-size edits in
144770
144988
  // a short Windows timestamp window indistinguishable to refresh.
144771
144989
  mtimeMs: Number(stat4.mtimeMs),
@@ -144775,8 +144993,8 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
144775
144993
  return {
144776
144994
  delta: {
144777
144995
  file,
144778
- symbols: extractSymbols(projectId, file, text, indexedAt),
144779
- edges: extractImportEdges(projectId, file, text, indexedAt)
144996
+ symbols: extractSymbols(projectId, file, text2, indexedAt),
144997
+ edges: extractImportEdges(projectId, file, text2, indexedAt)
144780
144998
  },
144781
144999
  unreadable: false
144782
145000
  };
@@ -145055,18 +145273,18 @@ __export(binder_exports, {
145055
145273
  function observationText(obs) {
145056
145274
  return [obs.title, obs.narrative, ...obs.facts ?? []].join("\n");
145057
145275
  }
145058
- function mentionsSymbol(text, symbol) {
145276
+ function mentionsSymbol(text2, symbol) {
145059
145277
  const name = symbol.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
145060
- return new RegExp(`(^|[^\\w$])${name}([^\\w$]|$)`).test(text);
145278
+ return new RegExp(`(^|[^\\w$])${name}([^\\w$]|$)`).test(text2);
145061
145279
  }
145062
- function identifierCandidates(text) {
145063
- return [...new Set(text.match(/[A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?/g) ?? [])];
145280
+ function identifierCandidates(text2) {
145281
+ return [...new Set(text2.match(/[A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?/g) ?? [])];
145064
145282
  }
145065
- function codeIdentifierCandidates(text) {
145283
+ function codeIdentifierCandidates(text2) {
145066
145284
  const explicit = /* @__PURE__ */ new Set();
145067
- for (const match2 of text.matchAll(/`([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)`/g)) explicit.add(match2[1]);
145068
- for (const match2 of text.matchAll(/\b([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)\s*\(/g)) explicit.add(match2[1]);
145069
- return identifierCandidates(text).filter((candidate) => explicit.has(candidate) || candidate.includes("::") || /[!?=]$/.test(candidate) || /^[A-Z]/.test(candidate) || /[_$]/.test(candidate) || /[a-z0-9][A-Z]/.test(candidate) || /[A-Z]{2}/.test(candidate));
145285
+ for (const match2 of text2.matchAll(/`([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)`/g)) explicit.add(match2[1]);
145286
+ for (const match2 of text2.matchAll(/\b([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)\s*\(/g)) explicit.add(match2[1]);
145287
+ return identifierCandidates(text2).filter((candidate) => explicit.has(candidate) || candidate.includes("::") || /[!?=]$/.test(candidate) || /^[A-Z]/.test(candidate) || /[_$]/.test(candidate) || /[a-z0-9][A-Z]/.test(candidate) || /[A-Z]{2}/.test(candidate));
145070
145288
  }
145071
145289
  function fileRef(projectId, obs, file) {
145072
145290
  return {
@@ -145096,7 +145314,7 @@ function symbolRef(projectId, obs, file, symbol) {
145096
145314
  }
145097
145315
  function resolveObservationCodeRefs(obs, lookup2) {
145098
145316
  const refs = /* @__PURE__ */ new Map();
145099
- const text = observationText(obs);
145317
+ const text2 = observationText(obs);
145100
145318
  const candidateFiles = /* @__PURE__ */ new Map();
145101
145319
  for (const rawPath of obs.filesModified ?? []) {
145102
145320
  const file = lookup2.findFile(normalizeCodePath(rawPath));
@@ -145106,7 +145324,7 @@ function resolveObservationCodeRefs(obs, lookup2) {
145106
145324
  refs.set(ref.id, ref);
145107
145325
  }
145108
145326
  const hintedFileIds = new Set(candidateFiles.keys());
145109
- const symbolNames = hintedFileIds.size > 0 ? identifierCandidates(text) : codeIdentifierCandidates(text);
145327
+ const symbolNames = hintedFileIds.size > 0 ? identifierCandidates(text2) : codeIdentifierCandidates(text2);
145110
145328
  const symbols = lookup2.findSymbols(symbolNames, [...hintedFileIds]);
145111
145329
  const symbolsByName = /* @__PURE__ */ new Map();
145112
145330
  for (const symbol of symbols) {
@@ -145117,7 +145335,7 @@ function resolveObservationCodeRefs(obs, lookup2) {
145117
145335
  for (const group of symbolsByName.values()) {
145118
145336
  const candidates = group.length === 1 ? group : [];
145119
145337
  for (const symbol of candidates) {
145120
- if (!mentionsSymbol(text, symbol)) continue;
145338
+ if (!mentionsSymbol(text2, symbol)) continue;
145121
145339
  const file = candidateFiles.get(symbol.fileId) ?? lookup2.findFile(symbol.path);
145122
145340
  if (!file) continue;
145123
145341
  candidateFiles.set(file.id, file);
@@ -145845,8 +146063,8 @@ function taskTokens(task) {
145845
146063
  return normalizedTokens(task);
145846
146064
  }
145847
146065
  function scoreClaim(claim, tokens) {
145848
- const text = [claim.subject, claim.predicate, claim.objectValue].join(" ").toLocaleLowerCase("en-US");
145849
- const words = normalizedTokens(text);
146066
+ const text2 = [claim.subject, claim.predicate, claim.objectValue].join(" ").toLocaleLowerCase("en-US");
146067
+ const words = normalizedTokens(text2);
145850
146068
  let matches = 0;
145851
146069
  for (const token of tokens) {
145852
146070
  if (words.has(token)) matches += 1;
@@ -146746,6 +146964,128 @@ var init_workflow_store = __esm({
146746
146964
  }
146747
146965
  });
146748
146966
 
146967
+ // src/knowledge/outcome-types.ts
146968
+ function qualityFromOutcome(signal) {
146969
+ if (!signal) return void 0;
146970
+ if (signal.kind === "verification-failed" || signal.kind === "user-correction" || signal.kind === "source-changed" || signal.kind === "conflict-confirmed") {
146971
+ return "degraded";
146972
+ }
146973
+ if (signal.kind === "verification-passed" || signal.kind === "verified-reuse" || signal.kind === "user-pin") {
146974
+ return "verified";
146975
+ }
146976
+ return void 0;
146977
+ }
146978
+ var MEMORY_OUTCOME_CANDIDATE_KINDS, MEMORY_OUTCOME_SIGNAL_KINDS;
146979
+ var init_outcome_types = __esm({
146980
+ "src/knowledge/outcome-types.ts"() {
146981
+ "use strict";
146982
+ init_esm_shims();
146983
+ MEMORY_OUTCOME_CANDIDATE_KINDS = ["claim", "durable-memory", "workflow"];
146984
+ MEMORY_OUTCOME_SIGNAL_KINDS = [
146985
+ "verification-passed",
146986
+ "verification-failed",
146987
+ "verified-reuse",
146988
+ "user-pin",
146989
+ "user-correction",
146990
+ "source-changed",
146991
+ "conflict-confirmed",
146992
+ "manual-review"
146993
+ ];
146994
+ }
146995
+ });
146996
+
146997
+ // src/knowledge/outcome-store.ts
146998
+ import { randomUUID as randomUUID10 } from "crypto";
146999
+ function optionalText4(value) {
147000
+ return typeof value === "string" && value.trim() ? value : void 0;
147001
+ }
147002
+ function text(value, field, max = 1e3) {
147003
+ const safe = sanitizeCredentials(value).replace(/\s+/g, " ").trim();
147004
+ if (!safe) throw new Error("Outcome signal " + field + " is required.");
147005
+ if (safe.length > max) throw new Error("Outcome signal " + field + " is too long.");
147006
+ return safe;
147007
+ }
147008
+ function oneOf(value, values, field) {
147009
+ if (typeof value !== "string" || !values.includes(value)) {
147010
+ throw new Error("Outcome signal " + field + " is invalid.");
147011
+ }
147012
+ return value;
147013
+ }
147014
+ function rowToSignal(row) {
147015
+ return {
147016
+ id: row.id,
147017
+ projectId: row.projectId,
147018
+ candidateKind: row.candidateKind,
147019
+ candidateId: row.candidateId,
147020
+ kind: row.kind,
147021
+ sourceRef: row.sourceRef,
147022
+ ...optionalText4(row.snapshotId) ? { snapshotId: row.snapshotId } : {},
147023
+ ...optionalText4(row.detail) ? { detail: row.detail } : {},
147024
+ observedAt: row.observedAt
147025
+ };
147026
+ }
147027
+ var OutcomeStore;
147028
+ var init_outcome_store = __esm({
147029
+ "src/knowledge/outcome-store.ts"() {
147030
+ "use strict";
147031
+ init_esm_shims();
147032
+ init_secret_filter();
147033
+ init_sqlite_db();
147034
+ init_outcome_types();
147035
+ OutcomeStore = class {
147036
+ db = null;
147037
+ async init(dataDir) {
147038
+ this.db = getDatabase(dataDir);
147039
+ }
147040
+ record(input) {
147041
+ const signal = {
147042
+ id: randomUUID10(),
147043
+ projectId: text(input.projectId, "project id"),
147044
+ candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
147045
+ candidateId: text(input.candidateId, "candidate id"),
147046
+ kind: oneOf(input.kind, MEMORY_OUTCOME_SIGNAL_KINDS, "kind"),
147047
+ sourceRef: text(input.sourceRef, "source reference"),
147048
+ ...input.snapshotId ? { snapshotId: text(input.snapshotId, "snapshot id") } : {},
147049
+ ...input.detail ? { detail: text(input.detail, "detail") } : {},
147050
+ observedAt: input.observedAt ?? (/* @__PURE__ */ new Date()).toISOString()
147051
+ };
147052
+ this.db.prepare(`
147053
+ INSERT INTO memory_outcome_signals (
147054
+ id, projectId, candidateKind, candidateId, kind, sourceRef, snapshotId, detail, observedAt
147055
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
147056
+ `).run(
147057
+ signal.id,
147058
+ signal.projectId,
147059
+ signal.candidateKind,
147060
+ signal.candidateId,
147061
+ signal.kind,
147062
+ signal.sourceRef,
147063
+ signal.snapshotId ?? null,
147064
+ signal.detail ?? null,
147065
+ signal.observedAt
147066
+ );
147067
+ return signal;
147068
+ }
147069
+ latestForCandidates(projectId, candidateKind, candidateIds) {
147070
+ const ids = [...new Set(candidateIds.filter(Boolean))];
147071
+ if (ids.length === 0) return /* @__PURE__ */ new Map();
147072
+ const placeholders = ids.map(() => "?").join(", ");
147073
+ const rows = this.db.prepare(`
147074
+ SELECT * FROM memory_outcome_signals
147075
+ WHERE projectId = ? AND candidateKind = ? AND candidateId IN (${placeholders})
147076
+ ORDER BY observedAt DESC, id DESC
147077
+ `).all(projectId, candidateKind, ...ids);
147078
+ const latest = /* @__PURE__ */ new Map();
147079
+ for (const row of rows) {
147080
+ const signal = rowToSignal(row);
147081
+ if (!latest.has(signal.candidateId)) latest.set(signal.candidateId, signal);
147082
+ }
147083
+ return latest;
147084
+ }
147085
+ };
147086
+ }
147087
+ });
147088
+
146749
147089
  // src/codegraph/task-lens.ts
146750
147090
  var task_lens_exports = {};
146751
147091
  __export(task_lens_exports, {
@@ -146762,31 +147102,31 @@ __export(task_lens_exports, {
146762
147102
  function normalizePath2(path33) {
146763
147103
  return path33.replace(/\\/g, "/");
146764
147104
  }
146765
- function tokenize3(text) {
146766
- return (text.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
147105
+ function tokenize3(text2) {
147106
+ return (text2.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
146767
147107
  }
146768
- function containsTaskKeyword(text, keyword) {
147108
+ function containsTaskKeyword(text2, keyword) {
146769
147109
  const matcher = /^[a-z0-9_-]+$/i.test(keyword) ? new RegExp(`(^|[^a-z0-9_-])${keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?=[^a-z0-9_-]|$)`, "gi") : new RegExp(keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
146770
147110
  let match2;
146771
- while ((match2 = matcher.exec(text)) !== null) {
147111
+ while ((match2 = matcher.exec(text2)) !== null) {
146772
147112
  const keywordIndex = match2.index + (match2[1]?.length ?? 0);
146773
- if (!isNegatedTaskKeyword(text, keywordIndex)) return true;
147113
+ if (!isNegatedTaskKeyword(text2, keywordIndex)) return true;
146774
147114
  }
146775
147115
  return false;
146776
147116
  }
146777
- function isNegatedTaskKeyword(text, keywordIndex) {
147117
+ function isNegatedTaskKeyword(text2, keywordIndex) {
146778
147118
  const boundary = Math.max(
146779
- text.lastIndexOf(".", keywordIndex - 1),
146780
- text.lastIndexOf("!", keywordIndex - 1),
146781
- text.lastIndexOf("?", keywordIndex - 1),
146782
- text.lastIndexOf(";", keywordIndex - 1),
146783
- text.lastIndexOf("\n", keywordIndex - 1),
146784
- text.lastIndexOf("\u3002", keywordIndex - 1),
146785
- text.lastIndexOf("\uFF01", keywordIndex - 1),
146786
- text.lastIndexOf("\uFF1F", keywordIndex - 1),
146787
- text.lastIndexOf("\uFF1B", keywordIndex - 1)
147119
+ text2.lastIndexOf(".", keywordIndex - 1),
147120
+ text2.lastIndexOf("!", keywordIndex - 1),
147121
+ text2.lastIndexOf("?", keywordIndex - 1),
147122
+ text2.lastIndexOf(";", keywordIndex - 1),
147123
+ text2.lastIndexOf("\n", keywordIndex - 1),
147124
+ text2.lastIndexOf("\u3002", keywordIndex - 1),
147125
+ text2.lastIndexOf("\uFF01", keywordIndex - 1),
147126
+ text2.lastIndexOf("\uFF1F", keywordIndex - 1),
147127
+ text2.lastIndexOf("\uFF1B", keywordIndex - 1)
146788
147128
  );
146789
- let prefix = text.slice(boundary + 1, keywordIndex).toLowerCase();
147129
+ let prefix = text2.slice(boundary + 1, keywordIndex).toLowerCase();
146790
147130
  const contrast = /(?:,|\uff0c)\s*(?:but|however|instead|yet|\u4f46\u662f|\u4f46|\u800c\u662f)\s*/gi;
146791
147131
  let contrastMatch;
146792
147132
  let contrastEnd = -1;
@@ -146809,9 +147149,9 @@ function resolveTaskLens(task) {
146809
147149
  };
146810
147150
  for (const id of LENS_PRIORITY) {
146811
147151
  const score = KEYWORDS[id].reduce((sum, keyword) => sum + (containsTaskKeyword(normalized, keyword) ? 1 : 0), 0);
146812
- const priority = LENS_PRIORITY.indexOf(id);
146813
- if (score > best.score || score === best.score && score > 0 && priority < best.priority) {
146814
- best = { id, score, priority };
147152
+ const priority2 = LENS_PRIORITY.indexOf(id);
147153
+ if (score > best.score || score === best.score && score > 0 && priority2 < best.priority) {
147154
+ best = { id, score, priority: priority2 };
146815
147155
  }
146816
147156
  }
146817
147157
  return best.score > 0 ? LENSES[best.id] : LENSES.general;
@@ -146853,20 +147193,20 @@ function pathKindScore(path33, lens) {
146853
147193
  return 0;
146854
147194
  }
146855
147195
  }
146856
- function tokenScore(text, tokens) {
147196
+ function tokenScore(text2, tokens) {
146857
147197
  if (tokens.length === 0) return 0;
146858
- const normalized = text.toLowerCase();
147198
+ const normalized = text2.toLowerCase();
146859
147199
  return tokens.reduce((sum, token) => sum + (normalized.includes(token) ? 12 : 0), 0);
146860
147200
  }
146861
147201
  function sourceTaskMatchScore(source, task) {
146862
147202
  const tokens = tokenize3(task ?? "");
146863
147203
  if (tokens.length === 0) return 0;
146864
- const text = [
147204
+ const text2 = [
146865
147205
  source.title,
146866
147206
  source.path ?? "",
146867
147207
  source.symbol ?? ""
146868
147208
  ].join("\n").toLowerCase();
146869
- const matches = tokens.filter((token) => text.includes(token)).length;
147209
+ const matches = tokens.filter((token) => text2.includes(token)).length;
146870
147210
  if (matches >= 2) return 40;
146871
147211
  if (matches === 1) return 24;
146872
147212
  return 0;
@@ -146905,8 +147245,8 @@ function lensPathCandidates(lens) {
146905
147245
  }
146906
147246
  function scoreLensSource(source, lens, task) {
146907
147247
  const tokens = tokenize3(task ?? "");
146908
- const text = [source.title, source.type, source.path ?? "", source.symbol ?? ""].join("\n");
146909
- return pathKindScore(source.path ?? "", lens) + tokenScore(text, tokens) + sourceTaskMatchScore(source, task);
147248
+ const text2 = [source.title, source.type, source.path ?? "", source.symbol ?? ""].join("\n");
147249
+ return pathKindScore(source.path ?? "", lens) + tokenScore(text2, tokens) + sourceTaskMatchScore(source, task);
146910
147250
  }
146911
147251
  function rankLensSources(sources, lens, task) {
146912
147252
  return [...sources].map((source, index) => ({
@@ -147149,7 +147489,7 @@ function requiredText(data, key) {
147149
147489
  }
147150
147490
  return value.trim();
147151
147491
  }
147152
- function optionalText4(data, key) {
147492
+ function optionalText5(data, key) {
147153
147493
  const value = data[key];
147154
147494
  if (value === void 0 || value === null || value === "") return void 0;
147155
147495
  if (typeof value !== "string") throw new Error("workflow frontmatter field " + key + " must be text");
@@ -147192,11 +147532,11 @@ function phaseFromValue(value, index) {
147192
147532
  }
147193
147533
  const data = value;
147194
147534
  const title = requiredText(data, "title");
147195
- const phaseId = optionalText4(data, "id") ?? slug(title) + "-" + (index + 1);
147535
+ const phaseId = optionalText5(data, "id") ?? slug(title) + "-" + (index + 1);
147196
147536
  return {
147197
147537
  id: phaseId,
147198
147538
  title,
147199
- instructions: optionalText4(data, "instructions") ?? "",
147539
+ instructions: optionalText5(data, "instructions") ?? "",
147200
147540
  branches: optionalStringArray(data, "branches"),
147201
147541
  expectedOutputs: optionalStringArray(data, "expectedOutputs"),
147202
147542
  verificationGates: optionalStringArray(data, "verificationGates")
@@ -147305,7 +147645,7 @@ function parsedWorkflow(data, body, input) {
147305
147645
  id: requiredText(data, "id"),
147306
147646
  workspaceId: input.workspaceId,
147307
147647
  title: requiredText(data, "title"),
147308
- description: optionalText4(data, "description") ?? "",
147648
+ description: optionalText5(data, "description") ?? "",
147309
147649
  status: optionalStatus(data),
147310
147650
  version: optionalNumber(data, "version", 1),
147311
147651
  taskLenses: optionalStringArray(data, "taskLenses"),
@@ -147324,9 +147664,9 @@ function parsedWorkflow(data, body, input) {
147324
147664
  sourcePath: normalizeSourcePath(input.sourcePath),
147325
147665
  sourceHash: "",
147326
147666
  contentHash: input.contentHash,
147327
- createdAt: optionalText4(data, "createdAt") ?? now2(),
147328
- updatedAt: optionalText4(data, "updatedAt") ?? now2(),
147329
- ...optionalText4(data, "importedFrom") ? { importedFrom: optionalText4(data, "importedFrom") } : {}
147667
+ createdAt: optionalText5(data, "createdAt") ?? now2(),
147668
+ updatedAt: optionalText5(data, "updatedAt") ?? now2(),
147669
+ ...optionalText5(data, "importedFrom") ? { importedFrom: optionalText5(data, "importedFrom") } : {}
147330
147670
  };
147331
147671
  if (candidate.phases.length === 0) {
147332
147672
  throw new Error("workflow must contain at least one phase or a non-empty body");
@@ -147425,11 +147765,11 @@ async function syncCanonicalWorkflows(workspace) {
147425
147765
  return { workflows, errors };
147426
147766
  }
147427
147767
  function inferTaskLenses(value) {
147428
- const text = value.toLowerCase();
147429
- return Object.entries(LENS_TERMS).filter(([, terms]) => terms.some((term) => text.includes(term))).map(([lens]) => lens);
147768
+ const text2 = value.toLowerCase();
147769
+ return Object.entries(LENS_TERMS).filter(([, terms]) => terms.some((term) => text2.includes(term))).map(([lens]) => lens);
147430
147770
  }
147431
147771
  function taskScore(workflow, task) {
147432
- const text = task.toLowerCase();
147772
+ const text2 = task.toLowerCase();
147433
147773
  let score = 0;
147434
147774
  const reasons = [];
147435
147775
  const matchedLenses = /* @__PURE__ */ new Set();
@@ -147696,7 +148036,31 @@ async function recordWorkflowRun(input) {
147696
148036
  throw new Error("Workflow was not found for this workspace");
147697
148037
  }
147698
148038
  if (!input.run.task.trim()) throw new Error("Workflow run task is required");
147699
- return store.recordRun(input.run);
148039
+ const run = store.recordRun(input.run);
148040
+ const kind = run.outcome === "passed" && run.verificationVerdict === "passed" ? "verification-passed" : run.outcome === "failed" || run.verificationVerdict === "failed" ? "verification-failed" : void 0;
148041
+ if (!kind) return run;
148042
+ const evidence = /* @__PURE__ */ new Map();
148043
+ evidence.set(workflow.id, "workflow");
148044
+ for (const reference of run.selectedEvidence) {
148045
+ const match2 = /^(claim|durable):(.+)$/.exec(reference);
148046
+ if (!match2) continue;
148047
+ evidence.set(match2[2], match2[1] === "claim" ? "claim" : "durable-memory");
148048
+ }
148049
+ const outcomes = new OutcomeStore();
148050
+ await outcomes.init(workflowStoreDataDir(input.workspace));
148051
+ for (const [candidateId, candidateKind] of evidence) {
148052
+ outcomes.record({
148053
+ projectId: run.projectId,
148054
+ candidateKind,
148055
+ candidateId,
148056
+ kind,
148057
+ sourceRef: "workflow-run:" + run.id,
148058
+ ...run.startingSnapshotId ? { snapshotId: run.startingSnapshotId } : {},
148059
+ ...run.failureReason ? { detail: run.failureReason } : {},
148060
+ observedAt: run.completedAt ?? run.startedAt
148061
+ });
148062
+ }
148063
+ return run;
147700
148064
  }
147701
148065
  async function selectWorkspaceWorkflows(input) {
147702
148066
  const synced = await syncCanonicalWorkflows(input.workspace);
@@ -147721,6 +148085,7 @@ var init_workflows2 = __esm({
147721
148085
  init_workflow_sync();
147722
148086
  init_workspace();
147723
148087
  init_workflow_store();
148088
+ init_outcome_store();
147724
148089
  init_task_lens();
147725
148090
  KNOWN_AGENTS = [
147726
148091
  "windsurf",
@@ -149746,8 +150111,8 @@ async function extractFactsWithLLM(narrative, title, existingFacts) {
149746
150111
  Content: ${narrative}${existingFacts.length > 0 ? `
149747
150112
  Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
149748
150113
  const response = await callLLM2(LLM_EXTRACT_PROMPT, input);
149749
- const text = response.content.trim();
149750
- const jsonMatch = text.match(/\{[\s\S]*\}/);
150114
+ const text2 = response.content.trim();
150115
+ const jsonMatch = text2.match(/\{[\s\S]*\}/);
149751
150116
  if (!jsonMatch) return [];
149752
150117
  const parsed = JSON.parse(jsonMatch[0]);
149753
150118
  const facts = parsed.facts;
@@ -150000,8 +150365,8 @@ Facts: ${extracted.facts.join("; ")}
150000
150365
  EXISTING MEMORIES:
150001
150366
  ${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Facts: ${m2.facts}`).join("\n")}`;
150002
150367
  const response = await callLLM2(LLM_RESOLVE_PROMPT, input);
150003
- const text = response.content.trim();
150004
- const jsonMatch = text.match(/\{[\s\S]*\}/);
150368
+ const text2 = response.content.trim();
150369
+ const jsonMatch = text2.match(/\{[\s\S]*\}/);
150005
150370
  if (!jsonMatch) return null;
150006
150371
  const parsed = JSON.parse(jsonMatch[0]);
150007
150372
  const action = parsed.action?.toUpperCase();
@@ -150782,8 +151147,8 @@ function isNoiseObservation(obs) {
150782
151147
  return NOISE_PATTERNS2.some((pattern) => pattern.test(title)) || isCommandTrace(obs);
150783
151148
  }
150784
151149
  function isSystemSelfObservation(obs) {
150785
- const text = stringifyObservation(obs, false);
150786
- return SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(text));
151150
+ const text2 = stringifyObservation(obs, false);
151151
+ return SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(text2));
150787
151152
  }
150788
151153
  function readerForAlias(reader, aliases, observation) {
150789
151154
  if (!reader) return void 0;
@@ -150806,8 +151171,8 @@ function continuationTaskTokens(task) {
150806
151171
  function continuationScore(observation, projectTokens, task) {
150807
151172
  let score = scoreObservationForSessionContext(observation, projectTokens);
150808
151173
  if (observation.type === "session-request" || observation.type === "what-changed") score += 1;
150809
- const text = stringifyObservation(observation);
150810
- const matches = continuationTaskTokens(task).filter((token) => text.includes(token)).length;
151174
+ const text2 = stringifyObservation(observation);
151175
+ const matches = continuationTaskTokens(task).filter((token) => text2.includes(token)).length;
150811
151176
  score += Math.min(matches, 2) * 2;
150812
151177
  return score;
150813
151178
  }
@@ -150841,8 +151206,8 @@ async function getSessionResumeBrief(projectId, task, reader) {
150841
151206
  memories
150842
151207
  };
150843
151208
  }
150844
- function compactResumeText(text, limit2) {
150845
- const normalized = text.replace(/\s+/g, " ").trim();
151209
+ function compactResumeText(text2, limit2) {
151210
+ const normalized = text2.replace(/\s+/g, " ").trim();
150846
151211
  return normalized.length <= limit2 ? normalized : `${normalized.slice(0, Math.max(0, limit2 - 3)).trimEnd()}...`;
150847
151212
  }
150848
151213
  function renderSessionResumeCard(brief) {
@@ -150864,11 +151229,11 @@ function renderSessionResumeCard(brief) {
150864
151229
  }
150865
151230
  function scoreObservationForSessionContext(obs, projectTokens, now3 = Date.now()) {
150866
151231
  let score = TYPE_WEIGHTS2[obs.type] ?? 1;
150867
- const text = stringifyObservation(obs);
151232
+ const text2 = stringifyObservation(obs);
150868
151233
  const ageDays = Math.max(0, (now3 - new Date(obs.createdAt).getTime()) / (1e3 * 60 * 60 * 24));
150869
151234
  score += Math.max(0.2, 2.5 - Math.min(ageDays, 45) * 0.05);
150870
151235
  if (projectTokens.length > 0) {
150871
- const matchingTokens = projectTokens.filter((token) => text.includes(token));
151236
+ const matchingTokens = projectTokens.filter((token) => text2.includes(token));
150872
151237
  if (matchingTokens.length > 0) {
150873
151238
  score += 2 + matchingTokens.length * 0.6;
150874
151239
  } else if ((obs.filesModified?.length ?? 0) > 0) {
@@ -151184,7 +151549,7 @@ var owner_exports = {};
151184
151549
  __export(owner_exports, {
151185
151550
  resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
151186
151551
  });
151187
- import { randomUUID as randomUUID10 } from "crypto";
151552
+ import { randomUUID as randomUUID11 } from "crypto";
151188
151553
  import { promises as fs17 } from "fs";
151189
151554
  import path25 from "path";
151190
151555
  function ownerPath(dataDir) {
@@ -151214,7 +151579,7 @@ async function resolveLocalMemoryOwner(dataDir, options = {}) {
151214
151579
  await fs17.mkdir(path25.dirname(filePath), { recursive: true });
151215
151580
  const created = {
151216
151581
  version: 1,
151217
- id: "local-" + randomUUID10(),
151582
+ id: "local-" + randomUUID11(),
151218
151583
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
151219
151584
  };
151220
151585
  try {
@@ -151237,8 +151602,8 @@ var init_owner = __esm({
151237
151602
  });
151238
151603
 
151239
151604
  // src/memory/long-term-store.ts
151240
- import { randomUUID as randomUUID11 } from "crypto";
151241
- function optionalText5(value) {
151605
+ import { randomUUID as randomUUID12 } from "crypto";
151606
+ function optionalText6(value) {
151242
151607
  return typeof value === "string" && value.trim() ? value : void 0;
151243
151608
  }
151244
151609
  function arrayValue2(value) {
@@ -151263,17 +151628,17 @@ function rowToMemory(row) {
151263
151628
  content: row.content,
151264
151629
  facts: arrayValue2(row.factsJson),
151265
151630
  tags: arrayValue2(row.tagsJson),
151266
- ...optionalText5(row.applicability) ? { applicability: row.applicability } : {},
151631
+ ...optionalText6(row.applicability) ? { applicability: row.applicability } : {},
151267
151632
  origin: row.origin,
151268
151633
  createdAt: row.createdAt,
151269
151634
  updatedAt: row.updatedAt,
151270
- ...optionalText5(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
151271
- ...optionalText5(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
151272
- ...optionalText5(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
151273
- ...optionalText5(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
151274
- ...optionalText5(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
151635
+ ...optionalText6(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
151636
+ ...optionalText6(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
151637
+ ...optionalText6(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
151638
+ ...optionalText6(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
151639
+ ...optionalText6(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
151275
151640
  accessCount: Number(row.accessCount ?? 0),
151276
- ...optionalText5(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
151641
+ ...optionalText6(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
151277
151642
  };
151278
151643
  }
151279
151644
  function rowToEvidence2(row) {
@@ -151283,8 +151648,8 @@ function rowToEvidence2(row) {
151283
151648
  kind: row.kind,
151284
151649
  referenceId: row.referenceId,
151285
151650
  relation: row.relation,
151286
- ...optionalText5(row.locator) ? { locator: row.locator } : {},
151287
- ...optionalText5(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
151651
+ ...optionalText6(row.locator) ? { locator: row.locator } : {},
151652
+ ...optionalText6(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
151288
151653
  createdAt: row.createdAt
151289
151654
  };
151290
151655
  }
@@ -151293,9 +151658,9 @@ function rowToEvent2(row) {
151293
151658
  id: row.id,
151294
151659
  memoryId: row.memoryId,
151295
151660
  kind: row.kind,
151296
- ...optionalText5(row.fromState) ? { fromState: row.fromState } : {},
151297
- ...optionalText5(row.toState) ? { toState: row.toState } : {},
151298
- ...optionalText5(row.detail) ? { detail: row.detail } : {},
151661
+ ...optionalText6(row.fromState) ? { fromState: row.fromState } : {},
151662
+ ...optionalText6(row.toState) ? { toState: row.toState } : {},
151663
+ ...optionalText6(row.detail) ? { detail: row.detail } : {},
151299
151664
  createdAt: row.createdAt
151300
151665
  };
151301
151666
  }
@@ -151397,7 +151762,7 @@ var init_long_term_store = __esm({
151397
151762
  }
151398
151763
  insertEvidence(input) {
151399
151764
  const evidence = {
151400
- id: randomUUID11(),
151765
+ id: randomUUID12(),
151401
151766
  ...input,
151402
151767
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
151403
151768
  };
@@ -151424,7 +151789,7 @@ var init_long_term_store = __esm({
151424
151789
  }
151425
151790
  recordEvent(input) {
151426
151791
  const event = {
151427
- id: randomUUID11(),
151792
+ id: randomUUID12(),
151428
151793
  ...input,
151429
151794
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
151430
151795
  };
@@ -151512,7 +151877,7 @@ __export(long_term_exports, {
151512
151877
  selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
151513
151878
  supersedeLongTermMemory: () => supersedeLongTermMemory
151514
151879
  });
151515
- import { randomUUID as randomUUID12 } from "crypto";
151880
+ import { randomUUID as randomUUID13 } from "crypto";
151516
151881
  function isOneOf(value, values) {
151517
151882
  return typeof value === "string" && values.includes(value);
151518
151883
  }
@@ -151694,7 +152059,7 @@ async function createManualLongTermMemory(input) {
151694
152059
  const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
151695
152060
  if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
151696
152061
  assertScope(input.scope);
151697
- const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID12(), relation: "supports" }];
152062
+ const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID13(), relation: "supports" }];
151698
152063
  return createLongTermMemoryWithDataDir({
151699
152064
  dataDir: input.dataDir,
151700
152065
  originProjectId: input.projectId,
@@ -151749,7 +152114,7 @@ async function createLongTermMemoryWithDataDir(input) {
151749
152114
  assertPortableEvidence(input.scope, portability, evidenceInputs);
151750
152115
  const now3 = (/* @__PURE__ */ new Date()).toISOString();
151751
152116
  const memory = {
151752
- id: randomUUID12(),
152117
+ id: randomUUID13(),
151753
152118
  originProjectId: compactText2(input.originProjectId, "origin project id", 1e3),
151754
152119
  ownerId: compactText2(input.ownerId, "owner id", 160),
151755
152120
  scope: input.scope,
@@ -152000,12 +152365,99 @@ var init_long_term = __esm({
152000
152365
  }
152001
152366
  });
152002
152367
 
152368
+ // src/knowledge/governor.ts
152369
+ function clampRelevance(value) {
152370
+ if (!Number.isFinite(value)) return 0;
152371
+ return Math.max(0, Math.min(1, value));
152372
+ }
152373
+ function classify(candidate) {
152374
+ const freshness = candidate.freshness ?? "unknown";
152375
+ const trust = candidate.trust ?? "historical";
152376
+ const quality = candidate.quality ?? "probationary";
152377
+ const conflict = candidate.conflict ?? "none";
152378
+ if (!candidate.scopeAllowed) {
152379
+ return { disposition: "exclude", reasons: ["scope-forbidden"] };
152380
+ }
152381
+ if (conflict === "confirmed") {
152382
+ return { disposition: "exclude", reasons: ["confirmed-conflict"] };
152383
+ }
152384
+ if (quality === "blocked") {
152385
+ return { disposition: "exclude", reasons: ["blocked-quality"] };
152386
+ }
152387
+ if (quality === "degraded") {
152388
+ return { disposition: "defer", reasons: ["degraded-quality"] };
152389
+ }
152390
+ if (freshness === "stale") {
152391
+ return { disposition: "defer", reasons: ["stale-evidence"] };
152392
+ }
152393
+ const reasons = [];
152394
+ let disposition = "include";
152395
+ if (freshness === "unknown") {
152396
+ disposition = "compact";
152397
+ reasons.push("unknown-freshness");
152398
+ }
152399
+ if (conflict === "possible") {
152400
+ disposition = "compact";
152401
+ reasons.push("possible-conflict");
152402
+ }
152403
+ if (quality === "probationary") {
152404
+ disposition = "compact";
152405
+ reasons.push("probationary-evidence");
152406
+ }
152407
+ if (disposition === "include" && freshness === "current" && trust === "source-backed") {
152408
+ reasons.push("current-source-backed-evidence");
152409
+ } else if (reasons.length === 0) {
152410
+ reasons.push("relevant-evidence");
152411
+ }
152412
+ return { disposition, reasons };
152413
+ }
152414
+ function priority(decision) {
152415
+ const dispositionWeight = {
152416
+ include: 3,
152417
+ compact: 2,
152418
+ defer: 1,
152419
+ exclude: 0
152420
+ };
152421
+ const evidence = Math.min(3, decision.candidate.evidenceCount ?? 0) / 10;
152422
+ return dispositionWeight[decision.disposition] + clampRelevance(decision.candidate.relevance) + evidence;
152423
+ }
152424
+ function governContextCandidates(candidates, maxTokens) {
152425
+ const safeBudget = Math.max(0, Math.floor(maxTokens));
152426
+ const decisions = candidates.map((candidate) => ({ candidate, ...classify(candidate) }));
152427
+ const eligible = decisions.filter((decision) => decision.disposition === "include" || decision.disposition === "compact").sort((left, right) => priority(right) - priority(left));
152428
+ let usedTokens = 0;
152429
+ for (const decision of eligible) {
152430
+ const tokens = Math.max(0, Math.ceil(decision.candidate.estimatedTokens));
152431
+ if (usedTokens + tokens <= safeBudget) {
152432
+ usedTokens += tokens;
152433
+ continue;
152434
+ }
152435
+ decision.disposition = "defer";
152436
+ decision.reasons = [...decision.reasons, "token-budget"];
152437
+ }
152438
+ const delivered = decisions.filter((decision) => decision.disposition === "include" || decision.disposition === "compact");
152439
+ const mode = delivered.length === 0 ? "abstain" : delivered.some((decision) => decision.disposition === "include") ? "workset" : "card";
152440
+ const cautions = [...new Set(decisions.filter((decision) => decision.disposition !== "include").flatMap((decision) => decision.reasons))];
152441
+ return {
152442
+ mode,
152443
+ budget: { maxTokens: safeBudget, usedTokens },
152444
+ decisions,
152445
+ cautions: cautions.length > 0 ? cautions : ["no-qualified-evidence"]
152446
+ };
152447
+ }
152448
+ var init_governor = __esm({
152449
+ "src/knowledge/governor.ts"() {
152450
+ "use strict";
152451
+ init_esm_shims();
152452
+ }
152453
+ });
152454
+
152003
152455
  // src/knowledge/workset.ts
152004
152456
  function unique(values) {
152005
152457
  return [...new Set(values.filter(Boolean))];
152006
152458
  }
152007
- function short(text, budget = 28) {
152008
- const safe = sanitizeCredentials(text).replace(/\s+/g, " ").trim();
152459
+ function short(text2, budget = 28) {
152460
+ const safe = sanitizeCredentials(text2).replace(/\s+/g, " ").trim();
152009
152461
  return countTextTokens(safe) <= budget ? safe : truncateToTokenBudget(safe, budget);
152010
152462
  }
152011
152463
  function claimAssertion(claim) {
@@ -152136,6 +152588,65 @@ function receiptOmissions(omitted, hiddenCautionMemoryCount) {
152136
152588
  function scheduledActions(cautions) {
152137
152589
  return cautions.filter((caution) => caution.kind === "codegraph-refresh-queued").map((caution) => short(caution.message, 28));
152138
152590
  }
152591
+ function isGovernedDelivery(disposition) {
152592
+ return disposition === "include" || disposition === "compact";
152593
+ }
152594
+ function governOptionalArtifacts(input) {
152595
+ const candidates = [
152596
+ ...input.reliableMemory.map((memory, index) => ({
152597
+ kind: "memory",
152598
+ id: "memory:" + memory.id,
152599
+ estimatedTokens: 10,
152600
+ relevance: Math.max(0.2, 0.9 - index * 0.1),
152601
+ scopeAllowed: true,
152602
+ freshness: freshnessForMemory(memory.status),
152603
+ trust: "historical",
152604
+ quality: memory.status === "current" ? "verified" : "degraded"
152605
+ })),
152606
+ ...input.claims.map((claim, index) => ({
152607
+ kind: "claim",
152608
+ id: "claim:" + claim.id,
152609
+ estimatedTokens: 12,
152610
+ relevance: Math.max(0.2, 0.95 - index * 0.1),
152611
+ scopeAllowed: true,
152612
+ freshness: claim.status === "active" ? "current" : "unknown",
152613
+ trust: "source-backed",
152614
+ quality: claim.reviewState === "approved" ? "verified" : "probationary",
152615
+ conflict: claim.status === "disputed" ? "confirmed" : "none",
152616
+ evidenceCount: claim.evidenceRefs.length
152617
+ })),
152618
+ ...input.durableMemory.map((memory, index) => ({
152619
+ kind: "durable-memory",
152620
+ id: "durable:" + memory.id,
152621
+ estimatedTokens: 14,
152622
+ relevance: Math.max(0.2, 0.8 - index * 0.1),
152623
+ scopeAllowed: true,
152624
+ freshness: memory.state === "approved" ? "current" : "unknown",
152625
+ trust: "source-backed",
152626
+ quality: memory.quality,
152627
+ evidenceCount: memory.evidenceRefs.length
152628
+ })),
152629
+ ...input.workflows.map((workflow, index) => ({
152630
+ kind: "workflow",
152631
+ id: "workflow:" + workflow.id,
152632
+ estimatedTokens: 14,
152633
+ relevance: Math.max(0.2, 0.85 - index * 0.1),
152634
+ scopeAllowed: true,
152635
+ freshness: "current",
152636
+ trust: "source-backed",
152637
+ quality: "verified"
152638
+ }))
152639
+ ];
152640
+ const plan = governContextCandidates(candidates, Number.MAX_SAFE_INTEGER);
152641
+ const permitted = new Set(plan.decisions.filter((decision) => isGovernedDelivery(decision.disposition)).map((decision) => decision.candidate.id));
152642
+ return {
152643
+ plan,
152644
+ reliableMemory: input.reliableMemory.filter((memory) => permitted.has("memory:" + memory.id)),
152645
+ claims: input.claims.filter((claim) => permitted.has("claim:" + claim.id)),
152646
+ durableMemory: input.durableMemory.filter((memory) => permitted.has("durable:" + memory.id)),
152647
+ workflows: input.workflows.filter((workflow) => permitted.has("workflow:" + workflow.id))
152648
+ };
152649
+ }
152139
152650
  function renderTaskWorksetPrompt(input) {
152140
152651
  const maxTokens = input.budget?.maxTokens ?? 180;
152141
152652
  const omitted = [];
@@ -152263,6 +152774,56 @@ function renderTaskWorksetPrompt(input) {
152263
152774
  trust: "source-backed"
152264
152775
  });
152265
152776
  }
152777
+ if (input.codeEvolution && input.codeEvolution.changes.length > 0) {
152778
+ appendLine(lines, "", maxTokens, omitted, "code-evolution-heading");
152779
+ appendLine(lines, "Code changes since prior scan", maxTokens, omitted, "code-evolution-heading");
152780
+ for (const change of input.codeEvolution.changes.slice(0, 3)) {
152781
+ appendLine(
152782
+ lines,
152783
+ "- " + change.kind + ": " + change.path,
152784
+ maxTokens,
152785
+ omitted,
152786
+ "code-evolution-change",
152787
+ selected,
152788
+ {
152789
+ kind: "code-state",
152790
+ id: "snapshot:" + input.codeEvolution.toSnapshotId,
152791
+ reason: "exact file hash change between complete CodeGraph snapshots",
152792
+ freshness: "current",
152793
+ trust: "source-backed"
152794
+ }
152795
+ );
152796
+ }
152797
+ for (const path33 of input.codeEvolution.directlyConnectedPaths.slice(0, 2)) {
152798
+ appendLine(
152799
+ lines,
152800
+ "- connected now: " + path33,
152801
+ maxTokens,
152802
+ omitted,
152803
+ "code-evolution-impact",
152804
+ selected,
152805
+ {
152806
+ kind: "code-state",
152807
+ id: "snapshot:" + input.codeEvolution.toSnapshotId,
152808
+ reason: "bounded current CodeGraph impact relation",
152809
+ freshness: "current",
152810
+ trust: "derived"
152811
+ }
152812
+ );
152813
+ }
152814
+ if ((input.codeEvolution.affectedMemoryCount ?? 0) > 0) {
152815
+ appendLine(
152816
+ lines,
152817
+ "- " + input.codeEvolution.affectedMemoryCount + " stored memory link(s) reference this changed code; reread source before relying on their conclusions.",
152818
+ maxTokens,
152819
+ omitted,
152820
+ "code-evolution-stale-memory"
152821
+ );
152822
+ }
152823
+ if (input.codeEvolution.truncated) {
152824
+ appendLine(lines, "- More connected files exist; inspect CodeGraph before assuming complete impact.", maxTokens, omitted, "code-evolution-truncated");
152825
+ }
152826
+ }
152266
152827
  if (input.semanticCode && (input.semanticCode.entryPoints.length > 0 || input.semanticCode.relations.length > 0)) {
152267
152828
  appendLine(lines, "", maxTokens, omitted, "semantic-code-heading");
152268
152829
  appendLine(lines, "Semantic code outline", maxTokens, omitted, "semantic-code-heading");
@@ -152453,6 +153014,17 @@ async function buildTaskWorkset(input) {
152453
153014
  }));
152454
153015
  let durableMemory = [];
152455
153016
  let durableEvidence = [];
153017
+ let outcomeStore;
153018
+ try {
153019
+ outcomeStore = new OutcomeStore();
153020
+ await outcomeStore.init(input.dataDir);
153021
+ } catch {
153022
+ }
153023
+ const claimQuality = outcomeStore ? outcomeStore.latestForCandidates(input.projectId, "claim", claims.map((claim) => claim.id)) : /* @__PURE__ */ new Map();
153024
+ for (const claim of claims) {
153025
+ const outcomeQuality = qualityFromOutcome(claimQuality.get(claim.id));
153026
+ if (outcomeQuality === "degraded") claim.reviewState = "needs-review";
153027
+ }
152456
153028
  if (task) {
152457
153029
  try {
152458
153030
  const selected = await selectLongTermMemoriesForTask({
@@ -152463,11 +153035,13 @@ async function buildTaskWorkset(input) {
152463
153035
  ...input.reader?.isTeamMember ? { isTeamMember: true } : {},
152464
153036
  limit: 3
152465
153037
  });
153038
+ const durableQuality = outcomeStore ? outcomeStore.latestForCandidates(input.projectId, "durable-memory", selected.map((item) => item.memory.id)) : /* @__PURE__ */ new Map();
152466
153039
  durableMemory = selected.map((item) => ({
152467
153040
  id: item.memory.id,
152468
153041
  kind: item.memory.kind,
152469
153042
  scope: item.memory.scope,
152470
153043
  state: item.memory.state,
153044
+ quality: qualityFromOutcome(durableQuality.get(item.memory.id)) ?? (item.memory.state === "approved" ? "verified" : "probationary"),
152471
153045
  title: item.memory.title,
152472
153046
  summary: renderLongTermMemorySummary(item.memory, 20),
152473
153047
  evidenceRefs: item.evidence.map((evidence) => evidence.id),
@@ -152513,18 +153087,25 @@ async function buildTaskWorkset(input) {
152513
153087
  }
152514
153088
  } catch {
152515
153089
  }
152516
- const evidenceIds = unique(selection.claims.flatMap((claim) => evidenceIdsForClaim(
152517
- claim,
152518
- evidenceByClaim.get(claim.id) ?? []
152519
- )).concat(
152520
- durableMemory.map((memory) => "durable:" + memory.id),
152521
- durableEvidence.map((evidence) => "durable-evidence:" + evidence.id)
152522
- ));
152523
153090
  const verification = unique([
152524
153091
  ...workflows.flatMap((workflow) => workflow.verificationGates),
152525
153092
  ...input.verificationHints
152526
153093
  ]).slice(0, 4);
152527
153094
  const normalizedCautions = unique(cautions.map((caution) => caution.kind)).map((kind) => cautions.find((caution) => caution.kind === kind)).slice(0, 6);
153095
+ const governed = governOptionalArtifacts({
153096
+ reliableMemory: input.reliableMemory?.slice(0, 3) ?? [],
153097
+ claims,
153098
+ durableMemory,
153099
+ workflows
153100
+ });
153101
+ const governedDurableIds = new Set(governed.durableMemory.map((memory) => memory.id));
153102
+ const evidenceIds = unique(governed.claims.flatMap((claim) => evidenceIdsForClaim(
153103
+ claim,
153104
+ evidenceByClaim.get(claim.id) ?? []
153105
+ )).concat(
153106
+ governed.durableMemory.map((memory) => "durable:" + memory.id),
153107
+ durableEvidence.filter((evidence) => governedDurableIds.has(evidence.memoryId)).map((evidence) => "durable-evidence:" + evidence.id)
153108
+ ));
152528
153109
  const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0 || input.continuation.compactCheckpoint) ? {
152529
153110
  ...input.continuation.previousSession ? {
152530
153111
  previousSession: {
@@ -152551,15 +153132,16 @@ async function buildTaskWorkset(input) {
152551
153132
  currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
152552
153133
  ...continuation ? { continuation } : {},
152553
153134
  ...input.codeState ? { codeState: short(input.codeState, 28) } : {},
153135
+ ...input.codeEvolution ? { codeEvolution: input.codeEvolution } : {},
152554
153136
  startHere: unique(input.startHere).slice(0, 5),
152555
153137
  ...input.semanticCode ? { semanticCode: input.semanticCode } : {},
152556
- reliableMemory: input.reliableMemory?.slice(0, 3) ?? [],
153138
+ reliableMemory: governed.reliableMemory,
152557
153139
  cautionMemory: input.cautionMemory?.slice(0, 3) ?? [],
152558
153140
  hiddenCautionMemoryCount: input.hiddenCautionMemoryCount ?? 0,
152559
- claims,
152560
- pages,
152561
- durableMemory,
152562
- workflows,
153141
+ claims: governed.claims,
153142
+ pages: pages.filter((page) => page.claimIds.some((claimId) => governed.claims.some((claim) => claim.id === claimId))),
153143
+ durableMemory: governed.durableMemory,
153144
+ workflows: governed.workflows,
152563
153145
  cautions: normalizedCautions,
152564
153146
  verification,
152565
153147
  evidenceIds,
@@ -152584,6 +153166,17 @@ async function buildTaskWorkset(input) {
152584
153166
  },
152585
153167
  selected: rendered.selected,
152586
153168
  omitted: receiptOmissions(rendered.omittedItems, base.hiddenCautionMemoryCount),
153169
+ governance: {
153170
+ scope: "optional-evidence",
153171
+ mode: governed.plan.mode,
153172
+ decisions: governed.plan.decisions.map((decision) => ({
153173
+ kind: decision.candidate.kind,
153174
+ ...decision.candidate.id ? { id: decision.candidate.id } : {},
153175
+ disposition: decision.disposition,
153176
+ reasons: decision.reasons
153177
+ })),
153178
+ cautions: governed.plan.cautions
153179
+ },
152587
153180
  scheduledActions: scheduledActions(normalizedCautions)
152588
153181
  };
152589
153182
  return {
@@ -152609,8 +153202,11 @@ var init_workset = __esm({
152609
153202
  init_workspace_store();
152610
153203
  init_workspace();
152611
153204
  init_workflow_store();
153205
+ init_outcome_store();
153206
+ init_outcome_types();
152612
153207
  init_workflows2();
152613
153208
  init_long_term();
153209
+ init_governor();
152614
153210
  CONTINUATION_DETAIL_TOKEN_BUDGET = 20;
152615
153211
  }
152616
153212
  });
@@ -152633,19 +153229,19 @@ function readTextIfExists(filePath) {
152633
153229
  }
152634
153230
  }
152635
153231
  function readPackageVersion(rootPath) {
152636
- const text = readTextIfExists(path26.join(rootPath, "package.json"));
152637
- if (!text) return void 0;
153232
+ const text2 = readTextIfExists(path26.join(rootPath, "package.json"));
153233
+ if (!text2) return void 0;
152638
153234
  try {
152639
- const parsed = JSON.parse(text);
153235
+ const parsed = JSON.parse(text2);
152640
153236
  return typeof parsed.version === "string" ? parsed.version : void 0;
152641
153237
  } catch {
152642
153238
  return void 0;
152643
153239
  }
152644
153240
  }
152645
153241
  function readLatestChangelog(rootPath) {
152646
- const text = readTextIfExists(path26.join(rootPath, "CHANGELOG.md"));
152647
- if (!text) return void 0;
152648
- const match2 = text.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
153242
+ const text2 = readTextIfExists(path26.join(rootPath, "CHANGELOG.md"));
153243
+ if (!text2) return void 0;
153244
+ const match2 = text2.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
152649
153245
  if (!match2) return void 0;
152650
153246
  return {
152651
153247
  version: match2[1],
@@ -152846,6 +153442,7 @@ function providerQuality(input) {
152846
153442
  capabilities: {
152847
153443
  declarations: true,
152848
153444
  importHints: true,
153445
+ localRelativeImportTargets: true,
152849
153446
  resolvedRelations: false,
152850
153447
  exactLocations: false
152851
153448
  },
@@ -153367,8 +153964,8 @@ var compaction_checkpoint_store_exports = {};
153367
153964
  __export(compaction_checkpoint_store_exports, {
153368
153965
  CompactionCheckpointStore: () => CompactionCheckpointStore
153369
153966
  });
153370
- import { createHash as createHash14, randomUUID as randomUUID13 } from "crypto";
153371
- function optionalText6(value) {
153967
+ import { createHash as createHash14, randomUUID as randomUUID14 } from "crypto";
153968
+ function optionalText7(value) {
153372
153969
  return typeof value === "string" && value ? value : void 0;
153373
153970
  }
153374
153971
  function optionalNumber2(value) {
@@ -153422,15 +154019,15 @@ function rowToCheckpoint(row) {
153422
154019
  reason: row.reason,
153423
154020
  sourceEvent: row.source_event,
153424
154021
  sourceKey: row.source_key,
153425
- ...optionalText6(row.summary) ? { summary: row.summary } : {},
154022
+ ...optionalText7(row.summary) ? { summary: row.summary } : {},
153426
154023
  ...optionalNumber2(row.tokens_before) !== void 0 ? { tokensBefore: Number(row.tokens_before) } : {},
153427
- ...optionalText6(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
154024
+ ...optionalText7(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
153428
154025
  ...parseDetails(row.details_json) ? { details: parseDetails(row.details_json) } : {},
153429
154026
  transcriptAvailable: Boolean(row.transcript_available),
153430
154027
  status: row.status,
153431
154028
  preCapturedAt: row.pre_captured_at,
153432
- ...optionalText6(row.completed_at) ? { completedAt: row.completed_at } : {},
153433
- ...optionalText6(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
154029
+ ...optionalText7(row.completed_at) ? { completedAt: row.completed_at } : {},
154030
+ ...optionalText7(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
153434
154031
  deliveryCount: Number(row.delivery_count ?? 0),
153435
154032
  createdAt: row.created_at,
153436
154033
  updatedAt: row.updated_at
@@ -153468,7 +154065,7 @@ var init_compaction_checkpoint_store = __esm({
153468
154065
  if (pending) return rowToCheckpoint(pending);
153469
154066
  const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
153470
154067
  const checkpoint = {
153471
- id: randomUUID13(),
154068
+ id: randomUUID14(),
153472
154069
  projectId: input.projectId,
153473
154070
  sessionId: input.sessionId,
153474
154071
  agent: input.agent,
@@ -153476,7 +154073,7 @@ var init_compaction_checkpoint_store = __esm({
153476
154073
  captureKind: "preflight",
153477
154074
  reason: safeReason(input.reason),
153478
154075
  sourceEvent: input.sourceEvent,
153479
- sourceKey: `pre:${randomUUID13()}`,
154076
+ sourceKey: `pre:${randomUUID14()}`,
153480
154077
  transcriptAvailable: Boolean(input.transcriptAvailable),
153481
154078
  status: "active",
153482
154079
  preCapturedAt: now3,
@@ -153542,7 +154139,7 @@ var init_compaction_checkpoint_store = __esm({
153542
154139
  return this.get(checkpoint2.id);
153543
154140
  }
153544
154141
  const checkpoint = {
153545
- id: randomUUID13(),
154142
+ id: randomUUID14(),
153546
154143
  projectId: input.projectId,
153547
154144
  sessionId: input.sessionId,
153548
154145
  agent: input.agent,
@@ -153804,6 +154401,25 @@ async function buildAutoProjectContext(input) {
153804
154401
  const overview = explain.overview;
153805
154402
  const currentFacts = collectCurrentProjectFacts({ project: input.project, now: now3 });
153806
154403
  const latestSnapshot = overview.code.latestSnapshot;
154404
+ let codeEvolution;
154405
+ if (continuationRequested && latestSnapshot?.previousSnapshotId && latestSnapshot.changedPathCount > 0) {
154406
+ const diff = store.diffSnapshots(input.project.id, latestSnapshot.previousSnapshotId, latestSnapshot.id);
154407
+ if (diff.available && diff.changes.length > 0) {
154408
+ const impact = store.impactSlice(input.project.id, diff.changes.map((change) => change.path));
154409
+ const changedFileIds = new Set([
154410
+ ...store.listSnapshotFiles(diff.fromSnapshotId),
154411
+ ...store.listSnapshotFiles(diff.toSnapshotId)
154412
+ ].filter((file) => diff.changes.some((change) => change.path === file.path)).map((file) => file.fileId));
154413
+ codeEvolution = {
154414
+ fromSnapshotId: diff.fromSnapshotId,
154415
+ toSnapshotId: diff.toSnapshotId,
154416
+ changes: diff.changes.slice(0, 5).map((change) => ({ path: change.path, kind: change.kind })),
154417
+ directlyConnectedPaths: impact.directlyConnectedPaths.slice(0, 3),
154418
+ affectedMemoryCount: store.countStaleObservationRefsForFiles(input.project.id, [...changedFileIds]),
154419
+ truncated: impact.truncated || diff.changes.length > 5
154420
+ };
154421
+ }
154422
+ }
153807
154423
  const sourceSets = lensSourceSets({ task, lens, explain });
153808
154424
  let externalOutline;
153809
154425
  let externalCaution;
@@ -153880,6 +154496,7 @@ async function buildAutoProjectContext(input) {
153880
154496
  currentFacts: worksetFactLines(currentFacts),
153881
154497
  ...continuation ? { continuation } : {},
153882
154498
  codeState: codeStateLine(overview),
154499
+ ...codeEvolution ? { codeEvolution } : {},
153883
154500
  reliableMemory: sourceSets.reliableSources.slice(0, lens.sourceLimit).map((source) => ({
153884
154501
  id: source.observationId,
153885
154502
  title: source.title,
@@ -153931,9 +154548,9 @@ async function buildAutoProjectContext(input) {
153931
154548
  function formatLanguages(overview) {
153932
154549
  return overview.code.languages.length > 0 ? overview.code.languages.map((item) => `${item.language} ${item.files}`).join(", ") : "none indexed yet";
153933
154550
  }
153934
- function compactContinuationText(text, budget) {
154551
+ function compactContinuationText(text2, budget) {
153935
154552
  return truncateToTokenBudget(
153936
- sanitizeCredentials(text).replace(/\s+/g, " ").trim(),
154553
+ sanitizeCredentials(text2).replace(/\s+/g, " ").trim(),
153937
154554
  budget
153938
154555
  );
153939
154556
  }
@@ -154208,8 +154825,8 @@ __export(context_pack_exports, {
154208
154825
  function uniq2(items) {
154209
154826
  return [...new Set(items)];
154210
154827
  }
154211
- function tokenize4(text) {
154212
- return (text.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1);
154828
+ function tokenize4(text2) {
154829
+ return (text2.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1);
154213
154830
  }
154214
154831
  function timestampOf(observation) {
154215
154832
  return Date.parse(observation.updatedAt ?? observation.createdAt ?? "") || 0;
@@ -154811,7 +155428,7 @@ __export(team_store_exports, {
154811
155428
  isTeamStoreInitialized: () => isTeamStoreInitialized,
154812
155429
  resetTeamStore: () => resetTeamStore
154813
155430
  });
154814
- import { randomUUID as randomUUID14 } from "crypto";
155431
+ import { randomUUID as randomUUID15 } from "crypto";
154815
155432
  import path28 from "path";
154816
155433
  import fs18 from "fs";
154817
155434
  function getTeamStore() {
@@ -155100,7 +155717,7 @@ var init_team_store = __esm({
155100
155717
  * reactivate it (preserving agent_id). Otherwise create a new one.
155101
155718
  */
155102
155719
  registerAgent(input) {
155103
- const instanceId = input.instanceId || randomUUID14();
155720
+ const instanceId = input.instanceId || randomUUID15();
155104
155721
  const now3 = Date.now();
155105
155722
  const existing = this.stmtAgentFindByInstance.get(
155106
155723
  input.projectId,
@@ -155126,7 +155743,7 @@ var init_team_store = __esm({
155126
155743
  this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
155127
155744
  return row2;
155128
155745
  }
155129
- const agentId = randomUUID14();
155746
+ const agentId = randomUUID15();
155130
155747
  this.stmtAgentUpsert.run({
155131
155748
  agent_id: agentId,
155132
155749
  project_id: input.projectId,
@@ -155228,7 +155845,7 @@ var init_team_store = __esm({
155228
155845
  return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
155229
155846
  }
155230
155847
  }
155231
- const id = randomUUID14();
155848
+ const id = randomUUID15();
155232
155849
  const now3 = Date.now();
155233
155850
  const row = {
155234
155851
  id,
@@ -155278,7 +155895,7 @@ var init_team_store = __esm({
155278
155895
  // Task Operations (with atomic claim semantics)
155279
155896
  // ═══════════════════════════════════════════════════════════════════
155280
155897
  createTask(input) {
155281
- const taskId = randomUUID14();
155898
+ const taskId = randomUUID15();
155282
155899
  const now3 = Date.now();
155283
155900
  const row = {
155284
155901
  task_id: taskId,
@@ -155550,7 +156167,7 @@ var init_team_store = __esm({
155550
156167
  for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
155551
156168
  for (const msg of msgs) {
155552
156169
  this.stmtMsgInsert.run({
155553
- id: msg.id ?? randomUUID14(),
156170
+ id: msg.id ?? randomUUID15(),
155554
156171
  project_id: "migrated",
155555
156172
  sender_agent_id: msg.from ?? "unknown",
155556
156173
  recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
@@ -155823,19 +156440,19 @@ function buildCompactionWorkset(checkpoint, options = {}) {
155823
156440
  const source = sanitizeCredentials(checkpoint.summary?.trim() || fallback);
155824
156441
  const available = Math.max(0, budget - countTextTokens(header) - 4);
155825
156442
  let excerpt = source ? truncateToTokenBudget(source, available) : "";
155826
- let text = `${header}${excerpt ? `### Host checkpoint
156443
+ let text2 = `${header}${excerpt ? `### Host checkpoint
155827
156444
  ${excerpt}` : ""}`.trim();
155828
- while (excerpt && countTextTokens(text) > budget) {
156445
+ while (excerpt && countTextTokens(text2) > budget) {
155829
156446
  const nextExcerptBudget = Math.max(1, Math.floor(countTextTokens(excerpt) * 0.8));
155830
156447
  excerpt = truncateToTokenBudget(excerpt, nextExcerptBudget);
155831
- text = `${header}${excerpt ? `### Host checkpoint
156448
+ text2 = `${header}${excerpt ? `### Host checkpoint
155832
156449
  ${excerpt}` : ""}`.trim();
155833
156450
  }
155834
- if (countTextTokens(text) > budget) text = truncateToTokenBudget(text, budget);
156451
+ if (countTextTokens(text2) > budget) text2 = truncateToTokenBudget(text2, budget);
155835
156452
  return {
155836
156453
  checkpointId: checkpoint.id,
155837
- text,
155838
- tokens: countTextTokens(text)
156454
+ text: text2,
156455
+ tokens: countTextTokens(text2)
155839
156456
  };
155840
156457
  }
155841
156458
  function sourceEvent(input) {
@@ -157726,15 +158343,15 @@ function validateSemantics(graph) {
157726
158343
  return warnings;
157727
158344
  }
157728
158345
  function extractJson(raw) {
157729
- let text = raw;
158346
+ let text2 = raw;
157730
158347
  try {
157731
158348
  const envelope = JSON.parse(raw.trim());
157732
158349
  if (envelope && typeof envelope.result === "string" && envelope.type === "result") {
157733
- text = envelope.result;
158350
+ text2 = envelope.result;
157734
158351
  }
157735
158352
  } catch {
157736
158353
  }
157737
- if (text === raw && raw.includes('"type"')) {
158354
+ if (text2 === raw && raw.includes('"type"')) {
157738
158355
  const textBlocks = [];
157739
158356
  for (const line of raw.split("\n")) {
157740
158357
  const trimmed = line.trim();
@@ -157758,27 +158375,27 @@ function extractJson(raw) {
157758
158375
  }
157759
158376
  }
157760
158377
  if (textBlocks.length > 0) {
157761
- text = textBlocks.join("");
158378
+ text2 = textBlocks.join("");
157762
158379
  }
157763
158380
  }
157764
- const fenced = text.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
158381
+ const fenced = text2.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
157765
158382
  if (fenced) {
157766
158383
  const candidate = fenced[1].trim();
157767
158384
  if (candidate.startsWith("{")) return candidate;
157768
158385
  }
157769
- const braceStart = text.indexOf("{");
158386
+ const braceStart = text2.indexOf("{");
157770
158387
  if (braceStart !== -1) {
157771
- const extracted = extractBalancedJson(text, braceStart);
158388
+ const extracted = extractBalancedJson(text2, braceStart);
157772
158389
  if (extracted) return extracted;
157773
158390
  }
157774
158391
  return null;
157775
158392
  }
157776
- function extractBalancedJson(text, startIdx) {
158393
+ function extractBalancedJson(text2, startIdx) {
157777
158394
  let depth = 0;
157778
158395
  let inString = false;
157779
158396
  let escape2 = false;
157780
- for (let i2 = startIdx; i2 < text.length; i2++) {
157781
- const ch = text[i2];
158397
+ for (let i2 = startIdx; i2 < text2.length; i2++) {
158398
+ const ch = text2[i2];
157782
158399
  if (escape2) {
157783
158400
  escape2 = false;
157784
158401
  continue;
@@ -157796,7 +158413,7 @@ function extractBalancedJson(text, startIdx) {
157796
158413
  else if (ch === "}") {
157797
158414
  depth--;
157798
158415
  if (depth === 0) {
157799
- return text.slice(startIdx, i2 + 1);
158416
+ return text2.slice(startIdx, i2 + 1);
157800
158417
  }
157801
158418
  }
157802
158419
  }
@@ -158015,7 +158632,7 @@ __export(planner_exports, {
158015
158632
  materializeTaskGraph: () => materializeTaskGraph,
158016
158633
  seedAutonomousPipeline: () => seedAutonomousPipeline
158017
158634
  });
158018
- import { randomUUID as randomUUID15 } from "crypto";
158635
+ import { randomUUID as randomUUID16 } from "crypto";
158019
158636
  function isPlannerTask(metadata) {
158020
158637
  if (!metadata) return null;
158021
158638
  try {
@@ -158073,7 +158690,7 @@ function seedAutonomousPipeline(teamStore, projectId, config, opts) {
158073
158690
  const maxIterations = config.maxIterations ?? 3;
158074
158691
  const taskBudget = config.taskBudget ?? 15;
158075
158692
  const structuredPlan = opts?.structuredPlan ?? true;
158076
- const pipelineId = randomUUID15();
158693
+ const pipelineId = randomUUID16();
158077
158694
  const meta = {
158078
158695
  plannerType: "plan",
158079
158696
  pipelineId,
@@ -158518,8 +159135,8 @@ async function callVisionLLM(systemPrompt, imageBase64, mimeType) {
158518
159135
  return data.choices[0]?.message?.content ?? "";
158519
159136
  }
158520
159137
  function normalizeText4(value, fallback = "") {
158521
- const text = typeof value === "string" && value.trim() ? value.trim() : fallback;
158522
- return sanitizeCredentials(text).slice(0, MAX_VISION_DESCRIPTION_CHARS);
159138
+ const text2 = typeof value === "string" && value.trim() ? value.trim() : fallback;
159139
+ return sanitizeCredentials(text2).slice(0, MAX_VISION_DESCRIPTION_CHARS);
158523
159140
  }
158524
159141
  function normalizeLabels(value) {
158525
159142
  if (!Array.isArray(value)) return [];
@@ -161209,7 +161826,7 @@ function evidenceScore2(obs) {
161209
161826
  }
161210
161827
  function scoreForPacket(obs, queryTokens, referenceTime, broadMemoryQuery) {
161211
161828
  let score = 0;
161212
- const text = normalizeText3([
161829
+ const text2 = normalizeText3([
161213
161830
  obs.title,
161214
161831
  obs.narrative,
161215
161832
  obs.entityName,
@@ -161218,15 +161835,15 @@ function scoreForPacket(obs, queryTokens, referenceTime, broadMemoryQuery) {
161218
161835
  ...obs.relatedEntities ?? [],
161219
161836
  ...obs.relatedCommits ?? []
161220
161837
  ].join(" "));
161221
- const matchingTokens = queryTokens.filter((token) => text.includes(token));
161838
+ const matchingTokens = queryTokens.filter((token) => text2.includes(token));
161222
161839
  score += matchingTokens.length * 4;
161223
161840
  if (queryTokens.length > 0 && matchingTokens.length === 0) {
161224
161841
  score -= 8;
161225
161842
  }
161226
- if (broadMemoryQuery && /memorix|memcode|memory-(?:graph|injection|runtime|quality|formation)|graph-context/.test(text)) {
161843
+ if (broadMemoryQuery && /memorix|memcode|memory-(?:graph|injection|runtime|quality|formation)|graph-context/.test(text2)) {
161227
161844
  score += 8;
161228
161845
  }
161229
- if (/\bmemory[- ]?game\b|e2e-test\/memory-game|team-handoff/.test(text)) {
161846
+ if (/\bmemory[- ]?game\b|e2e-test\/memory-game|team-handoff/.test(text2)) {
161230
161847
  score -= broadMemoryQuery ? 12 : 4;
161231
161848
  }
161232
161849
  score += obs.valueCategory === "core" ? 6 : 0;
@@ -164159,7 +164776,7 @@ The path should point to a directory containing a .git folder.`
164159
164776
  };
164160
164777
  const server = existingServer ?? new McpServer({
164161
164778
  name: "memorix",
164162
- version: true ? "1.4.1" : "1.0.1"
164779
+ version: true ? "1.4.2" : "1.0.1"
164163
164780
  });
164164
164781
  const originalRegisterTool = server.registerTool.bind(server);
164165
164782
  server.registerTool = ((name, ...args) => {
@@ -164895,10 +165512,10 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
164895
165512
  const duplicate = blockCoveredAutopilotEvidence("memorix_search", result.entries.map((entry) => entry.id), force);
164896
165513
  if (duplicate) return duplicate;
164897
165514
  }
164898
- let text = result.formatted;
165515
+ let text2 = result.formatted;
164899
165516
  try {
164900
165517
  const { getLastSearchMode: getLastSearchMode2 } = await Promise.resolve().then(() => (init_orama_store(), orama_store_exports));
164901
- text += `
165518
+ text2 += `
164902
165519
 
164903
165520
  _Search mode: ${getLastSearchMode2(project.id)}_`;
164904
165521
  } catch {
@@ -164907,7 +165524,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
164907
165524
  content: [
164908
165525
  {
164909
165526
  type: "text",
164910
- text
165527
+ text: text2
164911
165528
  }
164912
165529
  ]
164913
165530
  };
@@ -164940,14 +165557,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
164940
165557
  query,
164941
165558
  limit: limit2 != null ? coerceNumber(limit2, 5) : void 0
164942
165559
  });
164943
- const text = format === "summary" ? [
165560
+ const text2 = format === "summary" ? [
164944
165561
  `Graph context packet for ${project.name}`,
164945
165562
  `- ${packet.summary}`,
164946
165563
  "",
164947
165564
  ...packet.entities.map((entity) => `* ${entity.name} (#${entity.observationIds.join(", #")})`)
164948
165565
  ].join("\n") : formatGraphContextPrompt(packet);
164949
165566
  return {
164950
- content: [{ type: "text", text }]
165567
+ content: [{ type: "text", text: text2 }]
164951
165568
  };
164952
165569
  }
164953
165570
  );
@@ -165007,7 +165624,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165007
165624
  });
165008
165625
  }
165009
165626
  });
165010
- const text = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
165627
+ const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
165011
165628
  autopilotRetrievalBoundary = {
165012
165629
  projectId: project.id,
165013
165630
  issuedAt: Date.now(),
@@ -165019,7 +165636,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165019
165636
  readOnly: READ_ONLY_TASK_PATTERN.test(task ?? "")
165020
165637
  };
165021
165638
  return {
165022
- content: [{ type: "text", text }]
165639
+ content: [{ type: "text", text: text2 }]
165023
165640
  };
165024
165641
  }
165025
165642
  );
@@ -165147,9 +165764,9 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165147
165764
  ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
165148
165765
  reader: getObservationReader()
165149
165766
  });
165150
- const text = buildContextPackPrompt2(pack);
165767
+ const text2 = buildContextPackPrompt2(pack);
165151
165768
  return {
165152
- content: [{ type: "text", text }]
165769
+ content: [{ type: "text", text: text2 }]
165153
165770
  };
165154
165771
  }
165155
165772
  );
@@ -165211,7 +165828,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165211
165828
  }) => {
165212
165829
  const unresolved = requireResolvedProject("manage the Knowledge Workspace for the current project");
165213
165830
  if (unresolved) return unresolved;
165214
- const text = (value, isError = false) => ({
165831
+ const text2 = (value, isError = false) => ({
165215
165832
  content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
165216
165833
  ...isError ? { isError: true } : {}
165217
165834
  });
@@ -165248,7 +165865,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165248
165865
  ]);
165249
165866
  if (action === "workspace_init") {
165250
165867
  if (modeValue === "versioned" && !requireText(workspacePath, "path")) {
165251
- return text({ error: "path is required to initialize a versioned Knowledge Workspace." }, true);
165868
+ return text2({ error: "path is required to initialize a versioned Knowledge Workspace." }, true);
165252
165869
  }
165253
165870
  const workspace2 = await initializeKnowledgeWorkspace2({
165254
165871
  projectId: project.id,
@@ -165256,7 +165873,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165256
165873
  mode: modeValue,
165257
165874
  ...modeValue === "versioned" ? { projectRoot: project.rootPath, rootPath: requireText(workspacePath, "path") } : {}
165258
165875
  });
165259
- return text({
165876
+ return text2({
165260
165877
  workspace: {
165261
165878
  id: workspace2.id,
165262
165879
  mode: workspace2.mode,
@@ -165268,7 +165885,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165268
165885
  }
165269
165886
  const workspace = await loadKnowledgeWorkspace2({ projectId: project.id, dataDir: projectDir2, mode: modeValue });
165270
165887
  if (!workspace) {
165271
- return text({ error: "Knowledge Workspace is not initialized. Run workspace_init first." }, true);
165888
+ return text2({ error: "Knowledge Workspace is not initialized. Run workspace_init first." }, true);
165272
165889
  }
165273
165890
  const claims = new ClaimStore2();
165274
165891
  const workspaceStore = new KnowledgeWorkspaceStore2();
@@ -165276,7 +165893,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165276
165893
  if (action === "status") {
165277
165894
  const pages = workspaceStore.listPages(workspace.id);
165278
165895
  const pending = workspaceStore.listProposals(workspace.id, "pending");
165279
- return text({
165896
+ return text2({
165280
165897
  workspace: {
165281
165898
  id: workspace.id,
165282
165899
  mode: workspace.mode,
@@ -165294,7 +165911,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165294
165911
  });
165295
165912
  }
165296
165913
  if (action === "claim_list") {
165297
- return text({
165914
+ return text2({
165298
165915
  claims: claims.listClaims(project.id, { limit: 100 }).map((claim) => ({
165299
165916
  id: claim.id,
165300
165917
  subject: claim.subject,
@@ -165313,18 +165930,18 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165313
165930
  const requestedClaimId = requireText(claimId, "claimId");
165314
165931
  const detail = requireText(reviewDetail, "reviewDetail");
165315
165932
  if (!requestedClaimId || !claimReviewState || !detail) {
165316
- return text({ error: "claimId, claimReviewState, and reviewDetail are required for claim_review." }, true);
165933
+ return text2({ error: "claimId, claimReviewState, and reviewDetail are required for claim_review." }, true);
165317
165934
  }
165318
165935
  const existing = claims.getClaim(requestedClaimId);
165319
165936
  if (!existing || existing.projectId !== project.id) {
165320
- return text({ error: "Claim was not found for the current project." }, true);
165937
+ return text2({ error: "Claim was not found for the current project." }, true);
165321
165938
  }
165322
165939
  const claim = reviewClaim2(claims, {
165323
165940
  claimId: requestedClaimId,
165324
165941
  reviewState: claimReviewState,
165325
165942
  detail
165326
165943
  });
165327
- return text({
165944
+ return text2({
165328
165945
  claim: {
165329
165946
  id: claim.id,
165330
165947
  status: claim.status,
@@ -165336,7 +165953,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165336
165953
  }
165337
165954
  if (action === "compile") {
165338
165955
  const result = await compileKnowledgeWorkspace2({ workspace, claims });
165339
- return text({
165956
+ return text2({
165340
165957
  proposals: result.proposals.map((proposal) => ({
165341
165958
  id: proposal.id,
165342
165959
  targetPath: proposal.targetPath,
@@ -165351,17 +165968,17 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165351
165968
  const codeStore = new CodeGraphStore2();
165352
165969
  await codeStore.init(projectDir2);
165353
165970
  const result = await lintKnowledgeWorkspace2({ workspace, claims, codeStore });
165354
- return text(result);
165971
+ return text2(result);
165355
165972
  }
165356
165973
  if (action === "proposal_apply") {
165357
165974
  const proposal = requireText(proposalId, "proposalId");
165358
- if (!proposal) return text({ error: "proposalId is required for proposal_apply." }, true);
165975
+ if (!proposal) return text2({ error: "proposalId is required for proposal_apply." }, true);
165359
165976
  const result = await applyKnowledgeProposal2({
165360
165977
  workspace,
165361
165978
  proposalId: proposal,
165362
165979
  allowManualOverwrite: !!allowManualOverwrite
165363
165980
  });
165364
- return text({
165981
+ return text2({
165365
165982
  proposal: { id: result.proposal.id, status: result.proposal.status },
165366
165983
  targetPath: result.targetPath
165367
165984
  });
@@ -165371,7 +165988,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165371
165988
  const projectRoot = workspace.projectRoot ?? project.rootPath;
165372
165989
  if (action === "workflow_import") {
165373
165990
  const result = await importWindsurfWorkflows2({ workspace, projectRoot });
165374
- return text({
165991
+ return text2({
165375
165992
  imported: result.imported.map((workflow2) => ({
165376
165993
  id: workflow2.id,
165377
165994
  title: workflow2.title,
@@ -165384,7 +166001,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165384
166001
  }
165385
166002
  const synced = await syncCanonicalWorkflows2(workspace);
165386
166003
  if (action === "workflow_list") {
165387
- return text({
166004
+ return text2({
165388
166005
  workflows: workflowStore.listWorkflows(workspace.id).map((workflow2) => ({
165389
166006
  id: workflow2.id,
165390
166007
  title: workflow2.title,
@@ -165399,9 +166016,9 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165399
166016
  }
165400
166017
  if (action === "workflow_select") {
165401
166018
  const selectedTask = requireText(task, "task");
165402
- if (!selectedTask) return text({ error: "task is required for workflow_select." }, true);
166019
+ if (!selectedTask) return text2({ error: "task is required for workflow_select." }, true);
165403
166020
  const result = await selectWorkspaceWorkflows2({ workspace, task: selectedTask });
165404
- return text({
166021
+ return text2({
165405
166022
  selections: result.selections.map((selection) => ({
165406
166023
  id: selection.workflow.id,
165407
166024
  title: selection.workflow.title,
@@ -165413,16 +166030,16 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165413
166030
  });
165414
166031
  }
165415
166032
  const requestedWorkflowId = requireText(workflowId, "workflowId");
165416
- if (!requestedWorkflowId) return text({ error: "workflowId is required for this workflow action." }, true);
166033
+ if (!requestedWorkflowId) return text2({ error: "workflowId is required for this workflow action." }, true);
165417
166034
  const workflow = workflowStore.getWorkflow(requestedWorkflowId);
165418
166035
  if (!workflow || workflow.workspaceId !== workspace.id) {
165419
- return text({ error: "Workflow was not found for this Knowledge Workspace." }, true);
166036
+ return text2({ error: "Workflow was not found for this Knowledge Workspace." }, true);
165420
166037
  }
165421
166038
  if (action === "workflow_preview" || action === "workflow_apply") {
165422
166039
  const targetAgent = requireText(agent, "agent");
165423
- if (!targetAgent) return text({ error: "agent is required for a workflow adapter action." }, true);
166040
+ if (!targetAgent) return text2({ error: "agent is required for a workflow adapter action." }, true);
165424
166041
  const result = action === "workflow_preview" ? await previewWorkflowAdapter2({ workflow, projectRoot, agent: targetAgent }) : await applyWorkflowAdapter2({ workflow, projectRoot, agent: targetAgent });
165425
- return text({
166042
+ return text2({
165426
166043
  workflowId: workflow.id,
165427
166044
  agent: targetAgent,
165428
166045
  status: result.status,
@@ -165433,8 +166050,8 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165433
166050
  }
165434
166051
  if (action === "workflow_run") {
165435
166052
  const runTask = requireText(task, "task");
165436
- if (!runTask) return text({ error: "task is required for workflow_run." }, true);
165437
- if (!outcome) return text({ error: "outcome is required for workflow_run." }, true);
166053
+ if (!runTask) return text2({ error: "task is required for workflow_run." }, true);
166054
+ if (!outcome) return text2({ error: "outcome is required for workflow_run." }, true);
165438
166055
  const result = await recordWorkflowRun2({
165439
166056
  workspace,
165440
166057
  run: {
@@ -165448,14 +166065,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
165448
166065
  selectedEvidence: [...new Set((evidenceIds ?? []).map((item) => item.trim()).filter(Boolean))]
165449
166066
  }
165450
166067
  });
165451
- return text({
166068
+ return text2({
165452
166069
  id: result.id,
165453
166070
  workflowId: result.workflowId,
165454
166071
  outcome: result.outcome,
165455
166072
  verificationVerdict: result.verificationVerdict
165456
166073
  });
165457
166074
  }
165458
- return text({ error: "Unsupported knowledge action." }, true);
166075
+ return text2({ error: "Unsupported knowledge action." }, true);
165459
166076
  }
165460
166077
  );
165461
166078
  server.registerTool(
@@ -166930,10 +167547,10 @@ Ensure the path points to a directory containing a .git folder (or a subdirector
166930
167547
  ];
166931
167548
  const allSkills = await loadMiniSkills2(projectDir2, project.id);
166932
167549
  const miniSkills = allSkills.filter((s2) => {
166933
- const text = `${s2.title}
167550
+ const text2 = `${s2.title}
166934
167551
  ${s2.sourceEntity}
166935
167552
  ${s2.instruction}`.toLowerCase();
166936
- return !SKILL_NOISE.some((p) => p.test(text));
167553
+ return !SKILL_NOISE.some((p) => p.test(text2));
166937
167554
  });
166938
167555
  if (miniSkills.length > 0) {
166939
167556
  const formatted = formatMiniSkillsForInjection2(miniSkills);