memorix 1.4.0 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/CLAUDE.md +9 -9
  3. package/README.md +7 -2
  4. package/README.zh-CN.md +6 -2
  5. package/dist/cli/index.js +1216 -485
  6. package/dist/index.js +984 -337
  7. package/dist/maintenance-runner.js +564 -180
  8. package/dist/media-video-runner.js +564 -180
  9. package/dist/memcode/index.js +53 -21
  10. package/dist/memcode-runtime/CHANGELOG.md +31 -0
  11. package/dist/sdk.js +983 -336
  12. package/dist/vector-backfill-runner.js +564 -180
  13. package/docs/1.4.2-EVIDENCE-GOVERNED-MEMORY-SPEC.md +434 -0
  14. package/docs/API_REFERENCE.md +1 -1
  15. package/docs/KNOWN_ISSUES_AND_ROADMAP.md +52 -128
  16. package/package.json +5 -2
  17. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  18. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  19. package/plugins/copilot/memorix/plugin.json +1 -1
  20. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  21. package/plugins/omp/memorix/package.json +1 -1
  22. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  23. package/plugins/pi/memorix/package.json +1 -1
  24. package/server.json +2 -2
  25. package/src/cli/commands/codegraph.ts +83 -2
  26. package/src/codegraph/auto-context.ts +20 -0
  27. package/src/codegraph/current-facts.ts +1 -0
  28. package/src/codegraph/external-provider.ts +1 -0
  29. package/src/codegraph/store.ts +216 -5
  30. package/src/codegraph/types.ts +42 -0
  31. package/src/knowledge/context-assembly.ts +25 -0
  32. package/src/knowledge/governor.ts +156 -0
  33. package/src/knowledge/outcome-store.ts +102 -0
  34. package/src/knowledge/outcome-types.ts +49 -0
  35. package/src/knowledge/workflows.ts +32 -1
  36. package/src/knowledge/workset.ts +203 -13
  37. package/src/store/sqlite-db.ts +42 -0
  38. package/docs/dev-log/progress.txt +0 -388
package/dist/cli/index.js CHANGED
@@ -685,10 +685,10 @@ function createColors(useColor = isColorSupported) {
685
685
  function getColor(color, fallback = "reset") {
686
686
  return colors[color] || colors[fallback];
687
687
  }
688
- function stripAnsi(text) {
689
- return text.replace(new RegExp(ansiRegex, "g"), "");
688
+ function stripAnsi(text2) {
689
+ return text2.replace(new RegExp(ansiRegex, "g"), "");
690
690
  }
691
- function box(text, _opts = {}) {
691
+ function box(text2, _opts = {}) {
692
692
  const opts = {
693
693
  ..._opts,
694
694
  style: {
@@ -696,7 +696,7 @@ function box(text, _opts = {}) {
696
696
  ..._opts.style
697
697
  }
698
698
  };
699
- const textLines = text.split("\n");
699
+ const textLines = text2.split("\n");
700
700
  const boxLines = [];
701
701
  const _color = getColor(opts.style.borderColor);
702
702
  const borderStyle = {
@@ -3221,7 +3221,7 @@ ${import_picocolors.default.gray(m3)} ${s3}
3221
3221
 
3222
3222
  // src/cli/version.ts
3223
3223
  function getCliVersion() {
3224
- return true ? "1.4.0" : pkg.version;
3224
+ return true ? "1.4.2" : pkg.version;
3225
3225
  }
3226
3226
  var init_version = __esm({
3227
3227
  "src/cli/version.ts"() {
@@ -6944,14 +6944,14 @@ function normalizeToken(prop, token, withCache = true) {
6944
6944
  }
6945
6945
  return token;
6946
6946
  }
6947
- function trim(text) {
6948
- while (text[text.length - 1] === "") {
6949
- text.pop();
6947
+ function trim(text2) {
6948
+ while (text2[text2.length - 1] === "") {
6949
+ text2.pop();
6950
6950
  }
6951
- while (text[0] === "") {
6952
- text.shift();
6951
+ while (text2[0] === "") {
6952
+ text2.shift();
6953
6953
  }
6954
- return text;
6954
+ return text2;
6955
6955
  }
6956
6956
  function tokenize(input, language, prop, withCache = true) {
6957
6957
  if (language && language !== this.language) {
@@ -9363,7 +9363,7 @@ function closeAllDatabases() {
9363
9363
  _dbCache.delete(key);
9364
9364
  }
9365
9365
  }
9366
- 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;
9366
+ 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;
9367
9367
  var init_sqlite_db = __esm({
9368
9368
  "src/store/sqlite-db.ts"() {
9369
9369
  "use strict";
@@ -9629,6 +9629,17 @@ CREATE TABLE IF NOT EXISTS observation_code_refs (
9629
9629
  " UNIQUE(projectId, sourceEpoch)",
9630
9630
  ");"
9631
9631
  ].join("\n");
9632
+ CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE = [
9633
+ "CREATE TABLE IF NOT EXISTS code_state_snapshot_files (",
9634
+ " snapshotId TEXT NOT NULL,",
9635
+ " projectId TEXT NOT NULL,",
9636
+ " fileId TEXT NOT NULL,",
9637
+ " path TEXT NOT NULL,",
9638
+ " contentHash TEXT NOT NULL,",
9639
+ " PRIMARY KEY (snapshotId, path),",
9640
+ " FOREIGN KEY (snapshotId) REFERENCES code_state_snapshots(id) ON DELETE CASCADE",
9641
+ ");"
9642
+ ].join("\n");
9632
9643
  CREATE_KNOWLEDGE_CLAIMS_TABLE = `
9633
9644
  CREATE TABLE IF NOT EXISTS knowledge_claims (
9634
9645
  id TEXT PRIMARY KEY,
@@ -9839,6 +9850,19 @@ CREATE TABLE IF NOT EXISTS long_term_memory_events (
9839
9850
  createdAt TEXT NOT NULL,
9840
9851
  FOREIGN KEY (memoryId) REFERENCES long_term_memories(id) ON DELETE CASCADE
9841
9852
  );
9853
+ `;
9854
+ CREATE_MEMORY_OUTCOME_SIGNALS_TABLE = `
9855
+ CREATE TABLE IF NOT EXISTS memory_outcome_signals (
9856
+ id TEXT PRIMARY KEY,
9857
+ projectId TEXT NOT NULL,
9858
+ candidateKind TEXT NOT NULL,
9859
+ candidateId TEXT NOT NULL,
9860
+ kind TEXT NOT NULL,
9861
+ sourceRef TEXT NOT NULL,
9862
+ snapshotId TEXT,
9863
+ detail TEXT,
9864
+ observedAt TEXT NOT NULL
9865
+ );
9842
9866
  `;
9843
9867
  CREATE_MEDIA_ASSETS_TABLE = `
9844
9868
  CREATE TABLE IF NOT EXISTS media_assets (
@@ -10081,6 +10105,20 @@ CREATE UNIQUE INDEX IF NOT EXISTS idx_maintenance_jobs_active_dedupe
10081
10105
  db2.exec("CREATE INDEX IF NOT EXISTS idx_code_edges_snapshot ON code_edges(projectId, snapshotId)");
10082
10106
  }
10083
10107
  },
10108
+ {
10109
+ id: "1.4-codegraph-snapshot-manifest",
10110
+ apply: (db2) => {
10111
+ db2.exec(CREATE_CODE_STATE_SNAPSHOT_FILES_TABLE);
10112
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_code_snapshot_files_project_path ON code_state_snapshot_files(projectId, path)");
10113
+ }
10114
+ },
10115
+ {
10116
+ id: "1.4-memory-outcome-signals",
10117
+ apply: (db2) => {
10118
+ db2.exec(CREATE_MEMORY_OUTCOME_SIGNALS_TABLE);
10119
+ db2.exec("CREATE INDEX IF NOT EXISTS idx_memory_outcomes_candidate ON memory_outcome_signals(projectId, candidateKind, candidateId, observedAt DESC)");
10120
+ }
10121
+ },
10084
10122
  {
10085
10123
  id: "1.2-knowledge-claim-ledger",
10086
10124
  apply: (db2) => {
@@ -11112,14 +11150,14 @@ var init_BytePairEncodingCore = __esm({
11112
11150
  clearMergeCache() {
11113
11151
  this.mergeCache?.clear();
11114
11152
  }
11115
- *encodeNativeGenerator(text, allowedSpecial) {
11153
+ *encodeNativeGenerator(text2, allowedSpecial) {
11116
11154
  let startIndex = 0;
11117
11155
  let lastTokenLength = 0;
11118
11156
  while (true) {
11119
- const nextSpecialMatch = this.findNextSpecialToken(text, allowedSpecial, startIndex);
11157
+ const nextSpecialMatch = this.findNextSpecialToken(text2, allowedSpecial, startIndex);
11120
11158
  const nextSpecialStartIndex = nextSpecialMatch?.[0];
11121
- const endIndex = nextSpecialStartIndex ?? text.length;
11122
- const textBeforeSpecial = startIndex === 0 && endIndex === text.length ? text : text.slice(startIndex, endIndex);
11159
+ const endIndex = nextSpecialStartIndex ?? text2.length;
11160
+ const textBeforeSpecial = startIndex === 0 && endIndex === text2.length ? text2 : text2.slice(startIndex, endIndex);
11123
11161
  for (const [match2] of textBeforeSpecial.matchAll(this.tokenSplitRegex)) {
11124
11162
  const token = this.getBpeRankFromString(match2);
11125
11163
  if (token !== void 0) {
@@ -11146,14 +11184,14 @@ var init_BytePairEncodingCore = __esm({
11146
11184
  }
11147
11185
  return lastTokenLength;
11148
11186
  }
11149
- encodeNative(text, allowedSpecial) {
11187
+ encodeNative(text2, allowedSpecial) {
11150
11188
  let startIndex = 0;
11151
11189
  const tokensArray = [];
11152
11190
  while (true) {
11153
- const nextSpecialMatch = this.findNextSpecialToken(text, allowedSpecial, startIndex);
11191
+ const nextSpecialMatch = this.findNextSpecialToken(text2, allowedSpecial, startIndex);
11154
11192
  const nextSpecialStartIndex = nextSpecialMatch?.[0];
11155
- const endIndex = nextSpecialStartIndex ?? text.length;
11156
- const textBeforeSpecial = startIndex === 0 && endIndex === text.length ? text : text.slice(startIndex, endIndex);
11193
+ const endIndex = nextSpecialStartIndex ?? text2.length;
11194
+ const textBeforeSpecial = startIndex === 0 && endIndex === text2.length ? text2 : text2.slice(startIndex, endIndex);
11157
11195
  for (const [match2] of textBeforeSpecial.matchAll(this.tokenSplitRegex)) {
11158
11196
  const token = this.getBpeRankFromString(match2);
11159
11197
  if (token !== void 0) {
@@ -11177,14 +11215,14 @@ var init_BytePairEncodingCore = __esm({
11177
11215
  }
11178
11216
  return tokensArray;
11179
11217
  }
11180
- countNative(text, allowedSpecial) {
11218
+ countNative(text2, allowedSpecial) {
11181
11219
  let startIndex = 0;
11182
11220
  let tokensCount = 0;
11183
11221
  while (true) {
11184
- const nextSpecialMatch = this.findNextSpecialToken(text, allowedSpecial, startIndex);
11222
+ const nextSpecialMatch = this.findNextSpecialToken(text2, allowedSpecial, startIndex);
11185
11223
  const nextSpecialStartIndex = nextSpecialMatch?.[0];
11186
- const endIndex = nextSpecialStartIndex ?? text.length;
11187
- const textBeforeSpecial = startIndex === 0 && endIndex === text.length ? text : text.slice(startIndex, endIndex);
11224
+ const endIndex = nextSpecialStartIndex ?? text2.length;
11225
+ const textBeforeSpecial = startIndex === 0 && endIndex === text2.length ? text2 : text2.slice(startIndex, endIndex);
11188
11226
  for (const [match2] of textBeforeSpecial.matchAll(this.tokenSplitRegex)) {
11189
11227
  const token = this.getBpeRankFromString(match2);
11190
11228
  if (token !== void 0) {
@@ -11306,11 +11344,11 @@ var init_BytePairEncodingCore = __esm({
11306
11344
  }
11307
11345
  return -1;
11308
11346
  }
11309
- findNextSpecialToken(text, allowedSpecial, startIndex) {
11347
+ findNextSpecialToken(text2, allowedSpecial, startIndex) {
11310
11348
  let searchIndex = startIndex;
11311
11349
  while (true) {
11312
11350
  this.specialTokenPatternRegex.lastIndex = searchIndex;
11313
- const nextSpecialMatch = this.specialTokenPatternRegex.exec(text);
11351
+ const nextSpecialMatch = this.specialTokenPatternRegex.exec(text2);
11314
11352
  if (!nextSpecialMatch) {
11315
11353
  return void 0;
11316
11354
  }
@@ -12761,17 +12799,17 @@ var init_main = __esm({
12761
12799
  });
12762
12800
 
12763
12801
  // src/compact/token-budget.ts
12764
- function countTextTokens(text) {
12765
- return countTokens(text);
12802
+ function countTextTokens(text2) {
12803
+ return countTokens(text2);
12766
12804
  }
12767
- function fitsInBudget(text, limit2) {
12768
- return isWithinTokenLimit(text, limit2);
12805
+ function fitsInBudget(text2, limit2) {
12806
+ return isWithinTokenLimit(text2, limit2);
12769
12807
  }
12770
- function truncateToTokenBudget(text, budget) {
12771
- if (fitsInBudget(text, budget) !== false) {
12772
- return text;
12808
+ function truncateToTokenBudget(text2, budget) {
12809
+ if (fitsInBudget(text2, budget) !== false) {
12810
+ return text2;
12773
12811
  }
12774
- const sentences = text.split(/(?<=[.!?])\s+/);
12812
+ const sentences = text2.split(/(?<=[.!?])\s+/);
12775
12813
  let result = "";
12776
12814
  for (const sentence of sentences) {
12777
12815
  const candidate2 = result ? `${result} ${sentence}` : sentence;
@@ -12782,12 +12820,12 @@ function truncateToTokenBudget(text, budget) {
12782
12820
  }
12783
12821
  if (!result) {
12784
12822
  const estimatedChars = budget * 2;
12785
- result = text.slice(0, estimatedChars);
12823
+ result = text2.slice(0, estimatedChars);
12786
12824
  while (fitsInBudget(result, budget) === false && result.length > 0) {
12787
12825
  result = result.slice(0, Math.floor(result.length * 0.9));
12788
12826
  }
12789
- if (result.length < text.length) {
12790
- const nextCharacter = text.charAt(result.length);
12827
+ if (result.length < text2.length) {
12828
+ const nextCharacter = text2.charAt(result.length);
12791
12829
  if (nextCharacter && !/[\s.,;:!?)}\]]/.test(nextCharacter)) {
12792
12830
  const boundary = result.search(/\s+\S*$/);
12793
12831
  result = boundary > 0 ? result.slice(0, boundary).trimEnd() : "";
@@ -13665,8 +13703,8 @@ var require_main = __commonJS({
13665
13703
  function supportsAnsi() {
13666
13704
  return process.stdout.isTTY;
13667
13705
  }
13668
- function dim(text) {
13669
- return supportsAnsi() ? `\x1B[2m${text}\x1B[0m` : text;
13706
+ function dim(text2) {
13707
+ return supportsAnsi() ? `\x1B[2m${text2}\x1B[0m` : text2;
13670
13708
  }
13671
13709
  var LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg;
13672
13710
  function parse5(src2) {
@@ -14375,8 +14413,8 @@ import { createHash } from "crypto";
14375
14413
  import { readFile, writeFile, mkdir } from "fs/promises";
14376
14414
  import { join as join3 } from "path";
14377
14415
  import { homedir as homedir6 } from "os";
14378
- function textHash(text) {
14379
- return createHash("sha256").update(text).digest("hex").slice(0, 16);
14416
+ function textHash(text2) {
14417
+ return createHash("sha256").update(text2).digest("hex").slice(0, 16);
14380
14418
  }
14381
14419
  async function loadDiskCache() {
14382
14420
  try {
@@ -14439,11 +14477,11 @@ var init_fastembed_provider = __esm({
14439
14477
  async embedInputs(inputs, options2 = {}) {
14440
14478
  return Promise.all(inputs.map((input) => this.embedInput(input, options2)));
14441
14479
  }
14442
- async embed(text) {
14443
- const hash4 = textHash(text);
14480
+ async embed(text2) {
14481
+ const hash4 = textHash(text2);
14444
14482
  const cached2 = cache.get(hash4);
14445
14483
  if (cached2) return cached2;
14446
- const raw = await this.model.queryEmbed(text);
14484
+ const raw = await this.model.queryEmbed(text2);
14447
14485
  const result = Array.from(raw);
14448
14486
  if (result.length !== this.dimensions) {
14449
14487
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
@@ -14539,10 +14577,10 @@ var init_transformers_provider = __esm({
14539
14577
  async embedInputs(inputs, options2 = {}) {
14540
14578
  return Promise.all(inputs.map((input) => this.embedInput(input, options2)));
14541
14579
  }
14542
- async embed(text) {
14543
- const cached2 = cache2.get(text);
14580
+ async embed(text2) {
14581
+ const cached2 = cache2.get(text2);
14544
14582
  if (cached2) return cached2;
14545
- const output = await this.extractor(text, {
14583
+ const output = await this.extractor(text2, {
14546
14584
  pooling: "mean",
14547
14585
  normalize: true
14548
14586
  });
@@ -14550,7 +14588,7 @@ var init_transformers_provider = __esm({
14550
14588
  if (result.length !== this.dimensions) {
14551
14589
  throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);
14552
14590
  }
14553
- this.cacheSet(text, result);
14591
+ this.cacheSet(text2, result);
14554
14592
  return result;
14555
14593
  }
14556
14594
  async embedBatch(texts) {
@@ -14613,8 +14651,8 @@ function dimsCacheFile() {
14613
14651
  function cacheMetaFile() {
14614
14652
  return join4(cacheDir(), ".embedding-api-cache-meta.json");
14615
14653
  }
14616
- function normalizeText(text) {
14617
- return text.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
14654
+ function normalizeText(text2) {
14655
+ return text2.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
14618
14656
  }
14619
14657
  function cacheNamespace(config2) {
14620
14658
  return [
@@ -14624,8 +14662,8 @@ function cacheNamespace(config2) {
14624
14662
  config2.requestedDimensions ?? "native"
14625
14663
  ].join("|");
14626
14664
  }
14627
- function textHash2(text, namespace) {
14628
- return createHash2("sha256").update(`${namespace}\0${text}`).digest("hex").slice(0, 16);
14665
+ function textHash2(text2, namespace) {
14666
+ return createHash2("sha256").update(`${namespace}\0${text2}`).digest("hex").slice(0, 16);
14629
14667
  }
14630
14668
  function inputIdentity(input, options2 = {}) {
14631
14669
  return JSON.stringify({
@@ -15037,8 +15075,8 @@ var init_api_provider = __esm({
15037
15075
  if (!embedding) throw new Error("API probe returned no embeddings; check model name and API key");
15038
15076
  return embedding.length;
15039
15077
  }
15040
- async embed(text, options2) {
15041
- const normalized = normalizeText(text);
15078
+ async embed(text2, options2) {
15079
+ const normalized = normalizeText(text2);
15042
15080
  if (isNativeGeminiEndpoint(this.config.baseUrl)) {
15043
15081
  return this.embedInput({ modality: "text", text: normalized }, { intent: "document", ...options2 });
15044
15082
  }
@@ -15095,7 +15133,7 @@ var init_api_provider = __esm({
15095
15133
  }
15096
15134
  async embedBatch(texts, options2) {
15097
15135
  if (isNativeGeminiEndpoint(this.config.baseUrl)) {
15098
- return Promise.all(texts.map((text) => this.embedInput({ modality: "text", text }, { intent: "document", ...options2 })));
15136
+ return Promise.all(texts.map((text2) => this.embedInput({ modality: "text", text: text2 }, { intent: "document", ...options2 })));
15099
15137
  }
15100
15138
  await ensureDiskCacheLoaded();
15101
15139
  const normalizedTexts = texts.map(normalizeText);
@@ -15174,8 +15212,8 @@ var init_api_provider = __esm({
15174
15212
  }
15175
15213
  async getCachedEmbeddings(texts) {
15176
15214
  await ensureDiskCacheLoaded();
15177
- return texts.map((text) => {
15178
- const hash4 = textHash2(normalizeText(text), this.cacheKeyNamespace);
15215
+ return texts.map((text2) => {
15216
+ const hash4 = textHash2(normalizeText(text2), this.cacheKeyNamespace);
15179
15217
  return cache3.get(hash4) ?? null;
15180
15218
  });
15181
15219
  }
@@ -15405,9 +15443,9 @@ function wrapProvider(candidate2) {
15405
15443
  return {
15406
15444
  name: candidate2.name,
15407
15445
  dimensions: candidate2.dimensions,
15408
- async embed(text, options2) {
15446
+ async embed(text2, options2) {
15409
15447
  try {
15410
- return await candidate2.embed(text, options2);
15448
+ return await candidate2.embed(text2, options2);
15411
15449
  } catch (error40) {
15412
15450
  if (kind === "api" && getEmbeddingMode2() === "auto" && isTemporaryEmbeddingFailure(error40)) {
15413
15451
  warnOnce("[memorix] API embedding temporarily unavailable \u2014 switching to local fallback provider");
@@ -15415,7 +15453,7 @@ function wrapProvider(candidate2) {
15415
15453
  if (fallback) {
15416
15454
  provider = wrapProvider(fallback);
15417
15455
  warnOnce(`[memorix] Embedding fallback activated: ${provider.name} (${provider.dimensions}d)`);
15418
- return provider.embed(text, options2);
15456
+ return provider.embed(text2, options2);
15419
15457
  }
15420
15458
  }
15421
15459
  if (isTemporaryEmbeddingFailure(error40)) {
@@ -15974,8 +16012,8 @@ async function readResponseText(response, signal, maxBytes = MAX_LLM_RESPONSE_BY
15974
16012
  }
15975
16013
  }
15976
16014
  async function readResponseJson(response, signal, maxBytes = MAX_LLM_RESPONSE_BYTES) {
15977
- const text = await readResponseText(response, signal, maxBytes);
15978
- return JSON.parse(text);
16015
+ const text2 = await readResponseText(response, signal, maxBytes);
16016
+ return JSON.parse(text2);
15979
16017
  }
15980
16018
  async function* callLLMWithToolsStream(messages, tools) {
15981
16019
  if (!currentConfig) {
@@ -16528,8 +16566,8 @@ function isCjkHeavy(query) {
16528
16566
  const cjkCount = (query.match(CJK_PATTERN) || []).length;
16529
16567
  return query.length > 0 && cjkCount / query.length > 0.3;
16530
16568
  }
16531
- function normalizeExpansion(text) {
16532
- return text.trim().replace(/^[-*]\s*/, "").replace(/^["'`]+|["'`]+$/g, "").split(/\r?\n/)[0].trim();
16569
+ function normalizeExpansion(text2) {
16570
+ return text2.trim().replace(/^[-*]\s*/, "").replace(/^["'`]+|["'`]+$/g, "").split(/\r?\n/)[0].trim();
16533
16571
  }
16534
16572
  async function maybeExpandSearchQuery(query) {
16535
16573
  if (!query || !isCjkHeavy(query) || COMMAND_LIKE_QUERY.test(query)) {
@@ -16892,9 +16930,9 @@ function shouldSkipCompression(narrative, type) {
16892
16930
  if (specialChars / narrative.length > 0.35) return true;
16893
16931
  return false;
16894
16932
  }
16895
- function estimateTokens(text) {
16896
- const cjkChars = (text.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length;
16897
- const otherChars = text.length - cjkChars;
16933
+ function estimateTokens(text2) {
16934
+ const cjkChars = (text2.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length;
16935
+ const otherChars = text2.length - cjkChars;
16898
16936
  return Math.ceil(cjkChars / 1.5 + otherChars / 4);
16899
16937
  }
16900
16938
  var COMPRESS_PROMPT, COMPRESS_PROMPT_GENTLE, RERANK_PROMPT, SKIP_PATTERNS, LOW_COMPRESSION_TYPES;
@@ -17555,9 +17593,9 @@ var init_entity_extractor = __esm({
17555
17593
  });
17556
17594
 
17557
17595
  // src/memory/secret-filter.ts
17558
- function applyRedaction(text) {
17559
- if (!text) return text;
17560
- let out = text;
17596
+ function applyRedaction(text2) {
17597
+ if (!text2) return text2;
17598
+ let out = text2;
17561
17599
  out = out.replace(
17562
17600
  /((?:password|passwd|pwd|secret|token|api[_-]?key|auth[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret)\s*[:=]\s*["']?)([^\s"',;\n]{6,})/gi,
17563
17601
  "$1[REDACTED]"
@@ -17571,11 +17609,11 @@ function applyRedaction(text) {
17571
17609
  out = out.replace(/\beyJ[A-Za-z0-9._-]{40,}\b/g, "[REDACTED]");
17572
17610
  return out;
17573
17611
  }
17574
- function sanitizeCredentials(text) {
17575
- return applyRedaction(text);
17612
+ function sanitizeCredentials(text2) {
17613
+ return applyRedaction(text2);
17576
17614
  }
17577
- function redactCredentials(text) {
17578
- return applyRedaction(text);
17615
+ function redactCredentials(text2) {
17616
+ return applyRedaction(text2);
17579
17617
  }
17580
17618
  var init_secret_filter = __esm({
17581
17619
  "src/memory/secret-filter.ts"() {
@@ -17626,8 +17664,8 @@ function clampPositiveInteger(value, fallback) {
17626
17664
  return Math.max(1, Math.floor(value));
17627
17665
  }
17628
17666
  function errorText(error40) {
17629
- const text = error40 instanceof Error ? error40.message : String(error40);
17630
- return sanitizeCredentials(text).slice(0, MAX_ERROR_LENGTH);
17667
+ const text2 = error40 instanceof Error ? error40.message : String(error40);
17668
+ return sanitizeCredentials(text2).slice(0, MAX_ERROR_LENGTH);
17631
17669
  }
17632
17670
  function normalizedKinds(kinds) {
17633
17671
  if (!kinds) return void 0;
@@ -18721,9 +18759,9 @@ __export(consolidation_exports, {
18721
18759
  executeConsolidation: () => executeConsolidation,
18722
18760
  findConsolidationCandidates: () => findConsolidationCandidates
18723
18761
  });
18724
- function tokenize2(text) {
18762
+ function tokenize2(text2) {
18725
18763
  return new Set(
18726
- text.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff\s-]/g, " ").split(/\s+/).filter((t3) => t3.length > 1)
18764
+ text2.toLowerCase().replace(/[^a-z0-9\u4e00-\u9fff\s-]/g, " ").split(/\s+/).filter((t3) => t3.length > 1)
18727
18765
  );
18728
18766
  }
18729
18767
  function jaccardSimilarity(a3, b3) {
@@ -27875,8 +27913,8 @@ var init_headers = __esm({
27875
27913
  });
27876
27914
 
27877
27915
  // packages/ai/dist/utils/sanitize-unicode.js
27878
- function sanitizeSurrogates(text) {
27879
- return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
27916
+ function sanitizeSurrogates(text2) {
27917
+ return text2.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
27880
27918
  }
27881
27919
  var init_sanitize_unicode = __esm({
27882
27920
  "packages/ai/dist/utils/sanitize-unicode.js"() {
@@ -28358,9 +28396,9 @@ var init_values = __esm({
28358
28396
  }
28359
28397
  return n2;
28360
28398
  };
28361
- safeJSON = (text) => {
28399
+ safeJSON = (text2) => {
28362
28400
  try {
28363
- return JSON.parse(text);
28401
+ return JSON.parse(text2);
28364
28402
  } catch (err) {
28365
28403
  return void 0;
28366
28404
  }
@@ -29523,8 +29561,8 @@ async function defaultParseResponse(client, props) {
29523
29561
  const json4 = await response.json();
29524
29562
  return addRequestID(json4, response);
29525
29563
  }
29526
- const text = await response.text();
29527
- return text;
29564
+ const text2 = await response.text();
29565
+ return text2;
29528
29566
  })();
29529
29567
  loggerFor(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails({
29530
29568
  retryOfRequestLogID,
@@ -42894,7 +42932,7 @@ var init_models_generated = __esm({
42894
42932
  provider: "minimax",
42895
42933
  baseUrl: "https://api.minimax.io/anthropic",
42896
42934
  reasoning: true,
42897
- input: ["text", "image"],
42935
+ input: ["text", "image", "video"],
42898
42936
  cost: {
42899
42937
  input: 0.3,
42900
42938
  output: 1.2,
@@ -42947,7 +42985,7 @@ var init_models_generated = __esm({
42947
42985
  provider: "minimax-cn",
42948
42986
  baseUrl: "https://api.minimaxi.com/anthropic",
42949
42987
  reasoning: true,
42950
- input: ["text", "image"],
42988
+ input: ["text", "image", "video"],
42951
42989
  cost: {
42952
42990
  input: 0.3,
42953
42991
  output: 1.2,
@@ -55142,9 +55180,9 @@ var init_values2 = __esm({
55142
55180
  }
55143
55181
  return n2;
55144
55182
  };
55145
- safeJSON2 = (text) => {
55183
+ safeJSON2 = (text2) => {
55146
55184
  try {
55147
- return JSON.parse(text);
55185
+ return JSON.parse(text2);
55148
55186
  } catch (err) {
55149
55187
  return void 0;
55150
55188
  }
@@ -55918,8 +55956,8 @@ async function defaultParseResponse2(client, props) {
55918
55956
  const json4 = await response.json();
55919
55957
  return addRequestID2(json4, response);
55920
55958
  }
55921
- const text = await response.text();
55922
- return text;
55959
+ const text2 = await response.text();
55960
+ return text2;
55923
55961
  })();
55924
55962
  loggerFor2(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails2({
55925
55963
  retryOfRequestLogID,
@@ -62222,11 +62260,11 @@ var init_simple_options = __esm({
62222
62260
  });
62223
62261
 
62224
62262
  // packages/ai/dist/providers/transform-messages.js
62225
- function replaceImagesWithPlaceholder(content, placeholder) {
62263
+ function replaceMediaWithPlaceholder(content, dropType, placeholder) {
62226
62264
  const result = [];
62227
62265
  let previousWasPlaceholder = false;
62228
62266
  for (const block of content) {
62229
- if (block.type === "image") {
62267
+ if (block.type === dropType) {
62230
62268
  if (!previousWasPlaceholder) {
62231
62269
  result.push({ type: "text", text: placeholder });
62232
62270
  }
@@ -62234,33 +62272,39 @@ function replaceImagesWithPlaceholder(content, placeholder) {
62234
62272
  continue;
62235
62273
  }
62236
62274
  result.push(block);
62237
- previousWasPlaceholder = block.text === placeholder;
62275
+ previousWasPlaceholder = block.type === "text" && block.text === placeholder;
62238
62276
  }
62239
62277
  return result;
62240
62278
  }
62241
- function downgradeUnsupportedImages(messages, model) {
62242
- if (model.input.includes("image")) {
62279
+ function downgradeUnsupportedMedia(messages, model) {
62280
+ const supportsImage = model.input.includes("image");
62281
+ const supportsVideo = model.input.includes("video");
62282
+ if (supportsImage && supportsVideo) {
62243
62283
  return messages;
62244
62284
  }
62245
62285
  return messages.map((msg) => {
62246
62286
  if (msg.role === "user" && Array.isArray(msg.content)) {
62247
- return {
62248
- ...msg,
62249
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER)
62250
- };
62287
+ let content = msg.content;
62288
+ if (!supportsImage)
62289
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_USER_IMAGE_PLACEHOLDER);
62290
+ if (!supportsVideo)
62291
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_USER_VIDEO_PLACEHOLDER);
62292
+ return { ...msg, content };
62251
62293
  }
62252
62294
  if (msg.role === "toolResult") {
62253
- return {
62254
- ...msg,
62255
- content: replaceImagesWithPlaceholder(msg.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)
62256
- };
62295
+ let content = msg.content;
62296
+ if (!supportsImage)
62297
+ content = replaceMediaWithPlaceholder(content, "image", NON_VISION_TOOL_IMAGE_PLACEHOLDER);
62298
+ if (!supportsVideo)
62299
+ content = replaceMediaWithPlaceholder(content, "video", NON_VISION_TOOL_VIDEO_PLACEHOLDER);
62300
+ return { ...msg, content };
62257
62301
  }
62258
62302
  return msg;
62259
62303
  });
62260
62304
  }
62261
62305
  function transformMessages(messages, model, normalizeToolCallId2) {
62262
62306
  const toolCallIdMap = /* @__PURE__ */ new Map();
62263
- const imageAwareMessages = downgradeUnsupportedImages(messages, model);
62307
+ const imageAwareMessages = downgradeUnsupportedMedia(messages, model);
62264
62308
  const transformed = imageAwareMessages.map((msg) => {
62265
62309
  if (msg.role === "user") {
62266
62310
  return msg;
@@ -62372,13 +62416,15 @@ function transformMessages(messages, model, normalizeToolCallId2) {
62372
62416
  insertSyntheticToolResults();
62373
62417
  return result;
62374
62418
  }
62375
- var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER;
62419
+ var NON_VISION_USER_IMAGE_PLACEHOLDER, NON_VISION_TOOL_IMAGE_PLACEHOLDER, NON_VISION_USER_VIDEO_PLACEHOLDER, NON_VISION_TOOL_VIDEO_PLACEHOLDER;
62376
62420
  var init_transform_messages = __esm({
62377
62421
  "packages/ai/dist/providers/transform-messages.js"() {
62378
62422
  "use strict";
62379
62423
  init_esm_shims();
62380
62424
  NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
62381
62425
  NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
62426
+ NON_VISION_USER_VIDEO_PLACEHOLDER = "(video omitted: model does not support video)";
62427
+ NON_VISION_TOOL_VIDEO_PLACEHOLDER = "(tool video omitted: model does not support video)";
62382
62428
  }
62383
62429
  });
62384
62430
 
@@ -62409,8 +62455,8 @@ function getCacheControl(model, cacheRetention) {
62409
62455
  };
62410
62456
  }
62411
62457
  function convertContentBlocks(content) {
62412
- const hasImages = content.some((c5) => c5.type === "image");
62413
- if (!hasImages) {
62458
+ const hasMedia = content.some((c5) => c5.type === "image" || c5.type === "video");
62459
+ if (!hasMedia) {
62414
62460
  return sanitizeSurrogates(content.map((c5) => c5.text).join("\n"));
62415
62461
  }
62416
62462
  const blocks = content.map((block) => {
@@ -62420,6 +62466,16 @@ function convertContentBlocks(content) {
62420
62466
  text: sanitizeSurrogates(block.text)
62421
62467
  };
62422
62468
  }
62469
+ if (block.type === "video") {
62470
+ return {
62471
+ type: "video",
62472
+ source: {
62473
+ type: "base64",
62474
+ media_type: block.mimeType,
62475
+ data: block.data
62476
+ }
62477
+ };
62478
+ }
62423
62479
  return {
62424
62480
  type: "image",
62425
62481
  source: {
@@ -62433,7 +62489,7 @@ function convertContentBlocks(content) {
62433
62489
  if (!hasText) {
62434
62490
  blocks.unshift({
62435
62491
  type: "text",
62436
- text: "(see attached image)"
62492
+ text: "(see attached media)"
62437
62493
  });
62438
62494
  }
62439
62495
  return blocks;
@@ -62494,9 +62550,9 @@ function decodeSseLine(line, state) {
62494
62550
  }
62495
62551
  return null;
62496
62552
  }
62497
- function nextLineBreakIndex(text) {
62498
- const carriageReturnIndex = text.indexOf("\r");
62499
- const newlineIndex = text.indexOf("\n");
62553
+ function nextLineBreakIndex(text2) {
62554
+ const carriageReturnIndex = text2.indexOf("\r");
62555
+ const newlineIndex = text2.indexOf("\n");
62500
62556
  if (carriageReturnIndex === -1) {
62501
62557
  return newlineIndex;
62502
62558
  }
@@ -62505,18 +62561,18 @@ function nextLineBreakIndex(text) {
62505
62561
  }
62506
62562
  return Math.min(carriageReturnIndex, newlineIndex);
62507
62563
  }
62508
- function consumeLine(text) {
62509
- const lineBreakIndex = nextLineBreakIndex(text);
62564
+ function consumeLine(text2) {
62565
+ const lineBreakIndex = nextLineBreakIndex(text2);
62510
62566
  if (lineBreakIndex === -1) {
62511
62567
  return null;
62512
62568
  }
62513
62569
  let nextIndex = lineBreakIndex + 1;
62514
- if (text[lineBreakIndex] === "\r" && text[nextIndex] === "\n") {
62570
+ if (text2[lineBreakIndex] === "\r" && text2[nextIndex] === "\n") {
62515
62571
  nextIndex += 1;
62516
62572
  }
62517
62573
  return {
62518
- line: text.slice(0, lineBreakIndex),
62519
- rest: text.slice(nextIndex)
62574
+ line: text2.slice(0, lineBreakIndex),
62575
+ rest: text2.slice(nextIndex)
62520
62576
  };
62521
62577
  }
62522
62578
  async function* iterateSseMessages(body, signal) {
@@ -62783,6 +62839,15 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
62783
62839
  type: "text",
62784
62840
  text: sanitizeSurrogates(item.text)
62785
62841
  };
62842
+ } else if (item.type === "video") {
62843
+ return {
62844
+ type: "video",
62845
+ source: {
62846
+ type: "base64",
62847
+ media_type: item.mimeType,
62848
+ data: item.data
62849
+ }
62850
+ };
62786
62851
  } else {
62787
62852
  return {
62788
62853
  type: "image",
@@ -62863,6 +62928,8 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
62863
62928
  toolResults.push({
62864
62929
  type: "tool_result",
62865
62930
  tool_use_id: msg.toolCallId,
62931
+ // MiniMax's Anthropic-compatible API accepts video in tool results;
62932
+ // the SDK's ToolResultBlockParam.content type predates video support.
62866
62933
  content: convertContentBlocks(msg.content),
62867
62934
  is_error: msg.isError
62868
62935
  });
@@ -62889,7 +62956,7 @@ function convertMessages(messages, model, isOAuthToken2, cacheControl, allowEmpt
62889
62956
  if (lastMessage.role === "user") {
62890
62957
  if (Array.isArray(lastMessage.content)) {
62891
62958
  const lastBlock = lastMessage.content[lastMessage.content.length - 1];
62892
- if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "tool_result")) {
62959
+ if (lastBlock && (lastBlock.type === "text" || lastBlock.type === "image" || lastBlock.type === "video" || lastBlock.type === "tool_result")) {
62893
62960
  lastBlock.cache_control = cacheControl;
62894
62961
  }
62895
62962
  } else if (typeof lastMessage.content === "string") {
@@ -64672,8 +64739,8 @@ var require_common = __commonJS({
64672
64739
  }
64673
64740
  function redactString(obj, key) {
64674
64741
  if (typeof obj === "object" && obj !== null && typeof obj[key] === "string") {
64675
- const text = obj[key];
64676
- if (/grant_type=/i.test(text) || /assertion=/i.test(text) || /secret/i.test(text)) {
64742
+ const text2 = obj[key];
64743
+ if (/grant_type=/i.test(text2) || /assertion=/i.test(text2) || /secret/i.test(text2)) {
64677
64744
  obj[key] = REDACT;
64678
64745
  }
64679
64746
  }
@@ -71501,8 +71568,8 @@ var init_body = __esm({
71501
71568
  * @return Promise
71502
71569
  */
71503
71570
  async json() {
71504
- const text = await this.text();
71505
- return JSON.parse(text);
71571
+ const text2 = await this.text();
71572
+ return JSON.parse(text2);
71506
71573
  }
71507
71574
  /**
71508
71575
  * Decode response as text
@@ -72654,7 +72721,7 @@ var require_gaxios = __commonJS({
72654
72721
  var retry_js_1 = require_retry3();
72655
72722
  var stream_1 = __require("stream");
72656
72723
  var interceptor_js_1 = require_interceptor();
72657
- var randomUUID16 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
72724
+ var randomUUID17 = async () => globalThis.crypto?.randomUUID() || (await import("crypto")).randomUUID();
72658
72725
  var HTTP_STATUS_NO_CONTENT = 204;
72659
72726
  var Gaxios = class {
72660
72727
  agentCache = /* @__PURE__ */ new Map();
@@ -72927,7 +72994,7 @@ var require_gaxios = __commonJS({
72927
72994
  */
72928
72995
  ["Blob", "File", "FormData"].includes(opts.data?.constructor?.name || "");
72929
72996
  if (opts.multipart?.length) {
72930
- const boundary = await randomUUID16();
72997
+ const boundary = await randomUUID17();
72931
72998
  preparedHeaders.set("content-type", `multipart/related; boundary=${boundary}`);
72932
72999
  opts.body = stream_1.Readable.from(this.getMultipartRequest(opts.multipart, boundary));
72933
73000
  } else if (shouldDirectlyPassData) {
@@ -74678,18 +74745,18 @@ var require_parse = __commonJS({
74678
74745
  n: "\n",
74679
74746
  r: "\r",
74680
74747
  t: " "
74681
- }, text, error40 = function(m5) {
74748
+ }, text2, error40 = function(m5) {
74682
74749
  throw {
74683
74750
  name: "SyntaxError",
74684
74751
  message: m5,
74685
74752
  at,
74686
- text
74753
+ text: text2
74687
74754
  };
74688
74755
  }, next = function(c5) {
74689
74756
  if (c5 && c5 !== ch) {
74690
74757
  error40("Expected '" + c5 + "' instead of '" + ch + "'");
74691
74758
  }
74692
- ch = text.charAt(at);
74759
+ ch = text2.charAt(at);
74693
74760
  at += 1;
74694
74761
  return ch;
74695
74762
  }, number4 = function() {
@@ -74736,12 +74803,12 @@ var require_parse = __commonJS({
74736
74803
  var startAt = at;
74737
74804
  while (next()) {
74738
74805
  if (ch === '"') {
74739
- if (at - 1 > startAt) string5 += text.substring(startAt, at - 1);
74806
+ if (at - 1 > startAt) string5 += text2.substring(startAt, at - 1);
74740
74807
  next();
74741
74808
  return string5;
74742
74809
  }
74743
74810
  if (ch === "\\") {
74744
- if (at - 1 > startAt) string5 += text.substring(startAt, at - 1);
74811
+ if (at - 1 > startAt) string5 += text2.substring(startAt, at - 1);
74745
74812
  next();
74746
74813
  if (ch === "u") {
74747
74814
  uffff = 0;
@@ -74874,7 +74941,7 @@ var require_parse = __commonJS({
74874
74941
  };
74875
74942
  return function(source, reviver) {
74876
74943
  var result;
74877
- text = source + "";
74944
+ text2 = source + "";
74878
74945
  at = 0;
74879
74946
  ch = " ";
74880
74947
  result = value();
@@ -75786,8 +75853,8 @@ var require_crypto = __commonJS({
75786
75853
  const result = new TextDecoder().decode(uint8array);
75787
75854
  return result;
75788
75855
  }
75789
- encodeBase64StringUtf8(text) {
75790
- const uint8array = new TextEncoder().encode(text);
75856
+ encodeBase64StringUtf8(text2) {
75857
+ const uint8array = new TextEncoder().encode(text2);
75791
75858
  const result = base64js.fromByteArray(uint8array);
75792
75859
  return result;
75793
75860
  }
@@ -75856,8 +75923,8 @@ var require_crypto2 = __commonJS({
75856
75923
  decodeBase64StringUtf8(base643) {
75857
75924
  return Buffer.from(base643, "base64").toString("utf-8");
75858
75925
  }
75859
- encodeBase64StringUtf8(text) {
75860
- return Buffer.from(text, "utf-8").toString("base64");
75926
+ encodeBase64StringUtf8(text2) {
75927
+ return Buffer.from(text2, "utf-8").toString("base64");
75861
75928
  }
75862
75929
  /**
75863
75930
  * Computes the SHA-256 hash of the provided string.
@@ -96302,8 +96369,8 @@ async function defaultParseResponse3(client, props) {
96302
96369
  const json4 = await response.json();
96303
96370
  return json4;
96304
96371
  }
96305
- const text = await response.text();
96306
- return text;
96372
+ const text2 = await response.text();
96373
+ return text2;
96307
96374
  })();
96308
96375
  loggerFor3(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails3({
96309
96376
  retryOfRequestLogID,
@@ -97880,7 +97947,7 @@ var init_node = __esm({
97880
97947
  if (this.candidates && this.candidates.length > 1) {
97881
97948
  console.warn("there are multiple candidates in the response, returning text from the first one.");
97882
97949
  }
97883
- let text = "";
97950
+ let text2 = "";
97884
97951
  let anyTextPartText = false;
97885
97952
  const nonTextParts = [];
97886
97953
  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 : []) {
@@ -97894,13 +97961,13 @@ var init_node = __esm({
97894
97961
  continue;
97895
97962
  }
97896
97963
  anyTextPartText = true;
97897
- text += part.text;
97964
+ text2 += part.text;
97898
97965
  }
97899
97966
  }
97900
97967
  if (nonTextParts.length > 0) {
97901
97968
  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.`);
97902
97969
  }
97903
- return anyTextPartText ? text : void 0;
97970
+ return anyTextPartText ? text2 : void 0;
97904
97971
  }
97905
97972
  /**
97906
97973
  * Returns the concatenation of all inline data parts from the first candidate
@@ -98153,7 +98220,7 @@ var init_node = __esm({
98153
98220
  */
98154
98221
  get text() {
98155
98222
  var _a5, _b, _c;
98156
- let text = "";
98223
+ let text2 = "";
98157
98224
  let anyTextPartFound = false;
98158
98225
  const nonTextParts = [];
98159
98226
  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 : []) {
@@ -98167,13 +98234,13 @@ var init_node = __esm({
98167
98234
  continue;
98168
98235
  }
98169
98236
  anyTextPartFound = true;
98170
- text += part.text;
98237
+ text2 += part.text;
98171
98238
  }
98172
98239
  }
98173
98240
  if (nonTextParts.length > 0) {
98174
98241
  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.`);
98175
98242
  }
98176
- return anyTextPartFound ? text : void 0;
98243
+ return anyTextPartFound ? text2 : void 0;
98177
98244
  }
98178
98245
  /**
98179
98246
  * Returns the concatenation of all inline data parts from the server content if present.
@@ -102845,9 +102912,9 @@ var init_node = __esm({
102845
102912
  }
102846
102913
  return n2;
102847
102914
  };
102848
- safeJSON3 = (text) => {
102915
+ safeJSON3 = (text2) => {
102849
102916
  try {
102850
- return JSON.parse(text);
102917
+ return JSON.parse(text2);
102851
102918
  } catch (err) {
102852
102919
  return void 0;
102853
102920
  }
@@ -132448,8 +132515,8 @@ function findBoundary(buf) {
132448
132515
  return null;
132449
132516
  }
132450
132517
  function parseMessage2(chunk, parse5, state, dataRequired) {
132451
- const text = new TextDecoder().decode(chunk);
132452
- const lines = text.split(/\r\n|\r|\n/);
132518
+ const text2 = new TextDecoder().decode(chunk);
132519
+ const lines = text2.split(/\r\n|\r|\n/);
132453
132520
  const dataLines = [];
132454
132521
  const ret = {};
132455
132522
  let ignore = true;
@@ -159448,10 +159515,10 @@ function formatMistralError(error40) {
159448
159515
  }
159449
159516
  return safeJsonStringify(error40);
159450
159517
  }
159451
- function truncateErrorText(text, maxChars) {
159452
- if (text.length <= maxChars)
159453
- return text;
159454
- return `${text.slice(0, maxChars)}... [truncated ${text.length - maxChars} chars]`;
159518
+ function truncateErrorText(text2, maxChars) {
159519
+ if (text2.length <= maxChars)
159520
+ return text2;
159521
+ return `${text2.slice(0, maxChars)}... [truncated ${text2.length - maxChars} chars]`;
159455
159522
  }
159456
159523
  function safeJsonStringify(value) {
159457
159524
  try {
@@ -159571,7 +159638,7 @@ async function consumeChatStream(model, output, stream2, mistralStream) {
159571
159638
  continue;
159572
159639
  }
159573
159640
  if (item.type === "thinking") {
159574
- const deltaText = item.thinking.map((part) => "text" in part ? part.text : "").filter((text) => text.length > 0).join("");
159641
+ const deltaText = item.thinking.map((part) => "text" in part ? part.text : "").filter((text2) => text2.length > 0).join("");
159575
159642
  const thinkingDelta = sanitizeSurrogates(deltaText);
159576
159643
  if (!thinkingDelta)
159577
159644
  continue;
@@ -159768,8 +159835,8 @@ function toChatMessages(messages, supportsImages) {
159768
159835
  }
159769
159836
  return result;
159770
159837
  }
159771
- function buildToolResultText(text, hasImages, supportsImages, isError) {
159772
- const trimmed = text.trim();
159838
+ function buildToolResultText(text2, hasImages, supportsImages, isError) {
159839
+ const trimmed = text2.trim();
159773
159840
  const errorPrefix = isError ? "[tool error] " : "";
159774
159841
  if (trimmed.length > 0) {
159775
159842
  const imageSuffix = hasImages && !supportsImages ? "\n[tool image omitted: model does not support images]" : "";
@@ -160570,14 +160637,14 @@ async function* parseWebSocket(socket, signal, idleTimeoutMs) {
160570
160637
  };
160571
160638
  const onMessage = (event) => {
160572
160639
  void (async () => {
160573
- let text = null;
160640
+ let text2 = null;
160574
160641
  try {
160575
160642
  if (!event || typeof event !== "object" || !("data" in event))
160576
160643
  return;
160577
- text = await decodeWebSocketData(event.data);
160578
- if (!text)
160644
+ text2 = await decodeWebSocketData(event.data);
160645
+ if (!text2)
160579
160646
  return;
160580
- const parsed = JSON.parse(text);
160647
+ const parsed = JSON.parse(text2);
160581
160648
  const type = typeof parsed.type === "string" ? parsed.type : "";
160582
160649
  if (type === "response.completed" || type === "response.done" || type === "response.incomplete") {
160583
160650
  sawCompletion = true;
@@ -160588,7 +160655,7 @@ async function* parseWebSocket(socket, signal, idleTimeoutMs) {
160588
160655
  } catch (cause) {
160589
160656
  failed = new CodexProtocolError(`Invalid Codex WebSocket JSON: ${formatThrownValue(cause)}`, {
160590
160657
  cause,
160591
- payload: text
160658
+ payload: text2
160592
160659
  });
160593
160660
  done = true;
160594
160661
  wake();
@@ -168781,11 +168848,11 @@ function videoRequestConfig(input) {
168781
168848
  };
168782
168849
  }
168783
168850
  async function readMiniMaxJson(response) {
168784
- const text = await response.text();
168851
+ const text2 = await response.text();
168785
168852
  let body = {};
168786
- if (text) {
168853
+ if (text2) {
168787
168854
  try {
168788
- const parsed = JSON.parse(text);
168855
+ const parsed = JSON.parse(text2);
168789
168856
  if (isRecord2(parsed)) body = parsed;
168790
168857
  } catch {
168791
168858
  throw new Error("MiniMax video API returned invalid JSON");
@@ -169688,6 +169755,7 @@ __export(store_exports, {
169688
169755
  CodeGraphStore: () => CodeGraphStore
169689
169756
  });
169690
169757
  import { randomUUID as randomUUID6 } from "crypto";
169758
+ import { posix as pathPosix } from "path";
169691
169759
  function rowToFile(row) {
169692
169760
  return {
169693
169761
  id: row.id,
@@ -169738,6 +169806,26 @@ function rowToEdge(row) {
169738
169806
  ...row.sourceEpoch != null ? { sourceEpoch: Number(row.sourceEpoch) } : {}
169739
169807
  };
169740
169808
  }
169809
+ function resolveRelativeImportTarget(sourcePath, evidence, fileByPath) {
169810
+ const target = evidence?.trim().replace(/\\/g, "/");
169811
+ if (!target?.startsWith(".")) return void 0;
169812
+ const base = normalizeCodePath(pathPosix.normalize(pathPosix.join(pathPosix.dirname(sourcePath), target)));
169813
+ if (!base || base === ".." || base.startsWith("../")) return void 0;
169814
+ const candidates = [base];
169815
+ const extensionMatch = base.match(/(\.[A-Za-z0-9]+)$/);
169816
+ const hasExtension = Boolean(extensionMatch);
169817
+ if (!hasExtension) {
169818
+ const extensions = [...new Set([...fileByPath.keys()].map((path46) => path46.match(/(\.[A-Za-z0-9]+)$/)?.[1]).filter((extension3) => Boolean(extension3)))];
169819
+ for (const extension3 of extensions) {
169820
+ candidates.push(`${base}${extension3}`, `${base}/index${extension3}`);
169821
+ }
169822
+ } else {
169823
+ const sourceStem = base.slice(0, -extensionMatch[1].length);
169824
+ const sourceExtensions = extensionMatch[1] === ".js" ? [".ts", ".tsx", ".js", ".jsx"] : extensionMatch[1] === ".mjs" ? [".mts", ".mjs"] : extensionMatch[1] === ".cjs" ? [".cts", ".cjs"] : [];
169825
+ for (const extension3 of sourceExtensions) candidates.push(`${sourceStem}${extension3}`);
169826
+ }
169827
+ return candidates.map((candidate2) => fileByPath.get(candidate2)).find((file2) => Boolean(file2));
169828
+ }
169741
169829
  function rowToRef(row) {
169742
169830
  return {
169743
169831
  id: row.id,
@@ -169798,6 +169886,18 @@ function rowToSnapshot(row) {
169798
169886
  ...row.previousSnapshotId ? { previousSnapshotId: row.previousSnapshotId } : {}
169799
169887
  };
169800
169888
  }
169889
+ function rowToSnapshotFile(row) {
169890
+ return {
169891
+ snapshotId: row.snapshotId,
169892
+ projectId: row.projectId,
169893
+ fileId: row.fileId,
169894
+ path: row.path,
169895
+ contentHash: row.contentHash
169896
+ };
169897
+ }
169898
+ function snapshotIsIncomplete(snapshot) {
169899
+ return snapshot.completeness.skippedOversizedFiles > 0 || (snapshot.completeness.unreadableFiles ?? 0) > 0 || snapshot.completeness.removalScanDeferred;
169900
+ }
169801
169901
  var CodeGraphStore;
169802
169902
  var init_store = __esm({
169803
169903
  "src/codegraph/store.ts"() {
@@ -169969,6 +170069,7 @@ var init_store = __esm({
169969
170069
  }
169970
170070
  });
169971
170071
  tx();
170072
+ this.reconcileLocalImportTargets(projectId);
169972
170073
  }
169973
170074
  /**
169974
170075
  * Reconcile only files whose source changed plus files that disappeared.
@@ -169978,7 +170079,10 @@ var init_store = __esm({
169978
170079
  const changed = input.changed.filter((delta) => delta.file.projectId === projectId);
169979
170080
  const metadataOnly = (input.metadataOnly ?? []).filter((file2) => file2.projectId === projectId);
169980
170081
  const removedFileIds = input.removedFileIds ?? [];
169981
- if (changed.length === 0 && metadataOnly.length === 0 && removedFileIds.length === 0) return;
170082
+ if (changed.length === 0 && metadataOnly.length === 0 && removedFileIds.length === 0) {
170083
+ this.reconcileLocalImportTargets(projectId);
170084
+ return;
170085
+ }
169982
170086
  const staleRefsForFile = this.db.prepare(`
169983
170087
  UPDATE observation_code_refs
169984
170088
  SET status = 'stale', updatedAt = ?
@@ -169988,9 +170092,18 @@ var init_store = __esm({
169988
170092
  )
169989
170093
  )
169990
170094
  `);
169991
- const deleteEdgesForFile = this.db.prepare(`
170095
+ const deleteEdgesFromFile = this.db.prepare(`
169992
170096
  DELETE FROM code_edges
169993
- WHERE projectId = ? AND (fromFileId = ? OR toFileId = ?)
170097
+ WHERE projectId = ? AND fromFileId = ?
170098
+ `);
170099
+ const clearImportTargetsForFile = this.db.prepare(`
170100
+ UPDATE code_edges
170101
+ SET toFileId = NULL
170102
+ WHERE projectId = ? AND toFileId = ? AND type = 'imports'
170103
+ `);
170104
+ const deleteOtherIncomingEdgesForFile = this.db.prepare(`
170105
+ DELETE FROM code_edges
170106
+ WHERE projectId = ? AND toFileId = ? AND type != 'imports'
169994
170107
  `);
169995
170108
  const deleteSymbolsForFile = this.db.prepare(`DELETE FROM code_symbols WHERE projectId = ? AND fileId = ?`);
169996
170109
  const deleteFile = this.db.prepare(`DELETE FROM code_files WHERE projectId = ? AND id = ?`);
@@ -170027,14 +170140,18 @@ var init_store = __esm({
170027
170140
  const staleAt = (/* @__PURE__ */ new Date()).toISOString();
170028
170141
  for (const fileId of removedFileIds) {
170029
170142
  staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);
170030
- deleteEdgesForFile.run(projectId, fileId, fileId);
170143
+ deleteEdgesFromFile.run(projectId, fileId);
170144
+ clearImportTargetsForFile.run(projectId, fileId);
170145
+ deleteOtherIncomingEdgesForFile.run(projectId, fileId);
170031
170146
  deleteSymbolsForFile.run(projectId, fileId);
170032
170147
  deleteFile.run(projectId, fileId);
170033
170148
  }
170034
170149
  for (const delta of changed) {
170035
170150
  const fileId = delta.file.id;
170036
170151
  staleRefsForFile.run(staleAt, projectId, fileId, projectId, fileId);
170037
- deleteEdgesForFile.run(projectId, fileId, fileId);
170152
+ deleteEdgesFromFile.run(projectId, fileId);
170153
+ clearImportTargetsForFile.run(projectId, fileId);
170154
+ deleteOtherIncomingEdgesForFile.run(projectId, fileId);
170038
170155
  deleteSymbolsForFile.run(projectId, fileId);
170039
170156
  writeFile10(delta.file);
170040
170157
  for (const symbol2 of delta.symbols) {
@@ -170072,6 +170189,7 @@ var init_store = __esm({
170072
170189
  for (const file2 of metadataOnly) writeFile10(file2);
170073
170190
  });
170074
170191
  tx();
170192
+ this.reconcileLocalImportTargets(projectId);
170075
170193
  }
170076
170194
  upsertObservationRefs(refs) {
170077
170195
  if (refs.length === 0) return;
@@ -170133,6 +170251,25 @@ var init_store = __esm({
170133
170251
  });
170134
170252
  tx();
170135
170253
  }
170254
+ /**
170255
+ * Lite import extraction records the original import text first. Resolve only
170256
+ * local relative imports against the current index after each refresh, so an
170257
+ * added or removed target cannot leave a fabricated file-to-file relation.
170258
+ */
170259
+ reconcileLocalImportTargets(projectId) {
170260
+ const fileById = new Map(this.listFiles(projectId).map((file2) => [file2.id, file2]));
170261
+ const fileByPath = new Map([...fileById.values()].map((file2) => [file2.path, file2]));
170262
+ const update2 = this.db.prepare("UPDATE code_edges SET toFileId = ? WHERE id = ?");
170263
+ const tx = this.db.transaction(() => {
170264
+ for (const edge of this.listEdges(projectId)) {
170265
+ if (edge.type !== "imports" || !edge.fromFileId) continue;
170266
+ const source = fileById.get(edge.fromFileId);
170267
+ const target = source ? resolveRelativeImportTarget(source.path, edge.evidence, fileByPath) : void 0;
170268
+ update2.run(target?.id ?? null, edge.id);
170269
+ }
170270
+ });
170271
+ tx();
170272
+ }
170136
170273
  getFile(projectId, path46) {
170137
170274
  const row = this.db.prepare(`SELECT * FROM code_files WHERE projectId = ? AND path = ?`).get(projectId, normalizeCodePath(path46));
170138
170275
  return row ? rowToFile(row) : null;
@@ -170207,6 +170344,18 @@ var init_store = __esm({
170207
170344
  ORDER BY observationId, status, id
170208
170345
  `).all(projectId).map(rowToRef);
170209
170346
  }
170347
+ /** Count distinct observations whose binding to these exact files is stale. */
170348
+ countStaleObservationRefsForFiles(projectId, fileIds) {
170349
+ const ids = [...new Set(fileIds.filter(Boolean))];
170350
+ if (ids.length === 0) return 0;
170351
+ const placeholders = ids.map(() => "?").join(", ");
170352
+ const row = this.db.prepare(`
170353
+ SELECT COUNT(DISTINCT observationId) AS count
170354
+ FROM observation_code_refs
170355
+ WHERE projectId = ? AND status = 'stale' AND fileId IN (${placeholders})
170356
+ `).get(projectId, ...ids);
170357
+ return Number(row?.count ?? 0);
170358
+ }
170210
170359
  listReferencedSymbols(projectId) {
170211
170360
  return this.db.prepare(`
170212
170361
  SELECT DISTINCT symbols.*
@@ -170228,6 +170377,94 @@ var init_store = __esm({
170228
170377
  "SELECT * FROM code_state_snapshots WHERE projectId = ? ORDER BY sourceEpoch DESC LIMIT ?"
170229
170378
  ).all(projectId, safeLimit2).map(rowToSnapshot);
170230
170379
  }
170380
+ listSnapshotFiles(snapshotId) {
170381
+ return this.db.prepare(`
170382
+ SELECT snapshotId, projectId, fileId, path, contentHash
170383
+ FROM code_state_snapshot_files
170384
+ WHERE snapshotId = ?
170385
+ ORDER BY path
170386
+ `).all(snapshotId).map(rowToSnapshotFile);
170387
+ }
170388
+ diffSnapshots(projectId, fromSnapshotId, toSnapshotId) {
170389
+ const snapshots = this.db.prepare(`
170390
+ SELECT * FROM code_state_snapshots WHERE id IN (?, ?)
170391
+ `).all(fromSnapshotId, toSnapshotId).map(rowToSnapshot);
170392
+ if (snapshots.length !== 2) {
170393
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "missing-snapshot", changes: [] };
170394
+ }
170395
+ if (snapshots.some((snapshot) => snapshot.projectId !== projectId)) {
170396
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "project-mismatch", changes: [] };
170397
+ }
170398
+ if (snapshots.some(snapshotIsIncomplete)) {
170399
+ return { projectId, fromSnapshotId, toSnapshotId, available: false, reason: "incomplete-snapshot", changes: [] };
170400
+ }
170401
+ const before = this.listSnapshotFiles(fromSnapshotId);
170402
+ const after = this.listSnapshotFiles(toSnapshotId);
170403
+ if (before.length === 0 || after.length === 0) {
170404
+ return {
170405
+ projectId,
170406
+ fromSnapshotId,
170407
+ toSnapshotId,
170408
+ available: false,
170409
+ reason: "legacy-snapshot-without-manifest",
170410
+ changes: []
170411
+ };
170412
+ }
170413
+ const beforeByPath = new Map(before.map((file2) => [file2.path, file2]));
170414
+ const afterByPath = new Map(after.map((file2) => [file2.path, file2]));
170415
+ const paths = [.../* @__PURE__ */ new Set([...beforeByPath.keys(), ...afterByPath.keys()])].sort();
170416
+ const changes = [];
170417
+ for (const path46 of paths) {
170418
+ const oldFile = beforeByPath.get(path46);
170419
+ const newFile = afterByPath.get(path46);
170420
+ if (!oldFile && newFile) {
170421
+ changes.push({ path: path46, kind: "added", afterHash: newFile.contentHash });
170422
+ } else if (oldFile && !newFile) {
170423
+ changes.push({ path: path46, kind: "removed", beforeHash: oldFile.contentHash });
170424
+ } else if (oldFile && newFile && oldFile.contentHash !== newFile.contentHash) {
170425
+ changes.push({ path: path46, kind: "modified", beforeHash: oldFile.contentHash, afterHash: newFile.contentHash });
170426
+ }
170427
+ }
170428
+ return { projectId, fromSnapshotId, toSnapshotId, available: true, changes };
170429
+ }
170430
+ impactSlice(projectId, changedPaths, maxRelations = 24) {
170431
+ const safeLimit2 = Number.isFinite(maxRelations) ? Math.max(1, Math.min(100, Math.floor(maxRelations))) : 24;
170432
+ const normalizedPaths = [...new Set(changedPaths.map(normalizeCodePath).filter(Boolean))].sort();
170433
+ const files = this.listFiles(projectId);
170434
+ const fileById = new Map(files.map((file2) => [file2.id, file2.path]));
170435
+ const fileIdBySymbolId = new Map(this.listSymbols(projectId).map((symbol2) => [symbol2.id, symbol2.fileId]));
170436
+ const changedIds = new Set(files.filter((file2) => normalizedPaths.includes(file2.path)).map((file2) => file2.id));
170437
+ const direct = /* @__PURE__ */ new Set();
170438
+ let relationCount = 0;
170439
+ let truncated = false;
170440
+ for (const edge of this.listEdges(projectId)) {
170441
+ const endpoints = [
170442
+ edge.fromFileId,
170443
+ edge.toFileId,
170444
+ edge.fromSymbolId ? fileIdBySymbolId.get(edge.fromSymbolId) : void 0,
170445
+ edge.toSymbolId ? fileIdBySymbolId.get(edge.toSymbolId) : void 0
170446
+ ].filter((id) => Boolean(id));
170447
+ if (!endpoints.some((id) => changedIds.has(id))) continue;
170448
+ const relatedPaths = endpoints.filter((id) => !changedIds.has(id)).map((id) => fileById.get(id)).filter((path46) => Boolean(path46));
170449
+ if (relatedPaths.length === 0) continue;
170450
+ if (relationCount >= safeLimit2) {
170451
+ truncated = true;
170452
+ break;
170453
+ }
170454
+ relationCount += 1;
170455
+ for (const path46 of relatedPaths) direct.add(path46);
170456
+ }
170457
+ const snapshot = this.latestSnapshot(projectId);
170458
+ return {
170459
+ projectId,
170460
+ ...snapshot ? { snapshotId: snapshot.id } : {},
170461
+ changedPaths: normalizedPaths,
170462
+ directlyConnectedPaths: [...direct].sort(),
170463
+ relationCount,
170464
+ truncated,
170465
+ provider: snapshot?.provider ?? "lite"
170466
+ };
170467
+ }
170231
170468
  /**
170232
170469
  * Record a completed scan and mark all current structural facts with its
170233
170470
  * epoch. The snapshot is written only after refresh reconciliation succeeds,
@@ -170269,6 +170506,16 @@ var init_store = __esm({
170269
170506
  this.db.prepare(
170270
170507
  "UPDATE observation_code_refs SET snapshotId = ? WHERE projectId = ? AND status = 'current'"
170271
170508
  ).run(id, input.projectId);
170509
+ const snapshotFileRows = this.db.prepare(`
170510
+ SELECT id, projectId, path, contentHash FROM code_files WHERE projectId = ? ORDER BY path
170511
+ `).all(input.projectId);
170512
+ const insertSnapshotFile = this.db.prepare(`
170513
+ INSERT INTO code_state_snapshot_files (snapshotId, projectId, fileId, path, contentHash)
170514
+ VALUES (?, ?, ?, ?, ?)
170515
+ `);
170516
+ for (const file2 of snapshotFileRows) {
170517
+ insertSnapshotFile.run(id, file2.projectId, file2.id, file2.path, file2.contentHash);
170518
+ }
170272
170519
  snapshot = {
170273
170520
  ...input,
170274
170521
  id,
@@ -170434,8 +170681,8 @@ __export(lite_provider_exports, {
170434
170681
  import { createHash as createHash7 } from "crypto";
170435
170682
  import { readdirSync as readdirSync2, readFileSync as readFileSync7, statSync as statSync4 } from "fs";
170436
170683
  import { join as join5, relative } from "path";
170437
- function hashText(text) {
170438
- return createHash7("sha256").update(text).digest("hex");
170684
+ function hashText(text2) {
170685
+ return createHash7("sha256").update(text2).digest("hex");
170439
170686
  }
170440
170687
  function extension2(path46) {
170441
170688
  const index = path46.lastIndexOf(".");
@@ -170479,19 +170726,19 @@ function walk(root, exclude, maxFiles) {
170479
170726
  visit(root);
170480
170727
  return out;
170481
170728
  }
170482
- function lineOf(text, index) {
170483
- return text.slice(0, index).split(/\r?\n/).length;
170729
+ function lineOf(text2, index) {
170730
+ return text2.slice(0, index).split(/\r?\n/).length;
170484
170731
  }
170485
- function extractSymbols(projectId, file2, text, indexedAt) {
170732
+ function extractSymbols(projectId, file2, text2, indexedAt) {
170486
170733
  const symbols = [];
170487
170734
  const profile = file2.language ? languageProfiles[file2.language] : void 0;
170488
170735
  const patterns = profile?.symbols ?? [];
170489
170736
  for (const { kind, re: re2 } of patterns) {
170490
170737
  re2.lastIndex = 0;
170491
- for (const match2 of text.matchAll(re2)) {
170738
+ for (const match2 of text2.matchAll(re2)) {
170492
170739
  const name = match2[1];
170493
170740
  if (!name || name.includes("\n")) continue;
170494
- const startLine = lineOf(text, match2.index ?? 0);
170741
+ const startLine = lineOf(text2, match2.index ?? 0);
170495
170742
  const id = makeCodeSymbolId({ projectId, path: file2.path, qualifiedName: name, kind });
170496
170743
  symbols.push({
170497
170744
  id,
@@ -170511,13 +170758,13 @@ function extractSymbols(projectId, file2, text, indexedAt) {
170511
170758
  }
170512
170759
  return symbols;
170513
170760
  }
170514
- function extractImportEdges(projectId, file2, text, indexedAt) {
170761
+ function extractImportEdges(projectId, file2, text2, indexedAt) {
170515
170762
  const edges = [];
170516
170763
  const profile = file2.language ? languageProfiles[file2.language] : void 0;
170517
170764
  const imports = profile?.imports ?? [];
170518
170765
  for (const re2 of imports) {
170519
170766
  re2.lastIndex = 0;
170520
- for (const match2 of text.matchAll(re2)) {
170767
+ for (const match2 of text2.matchAll(re2)) {
170521
170768
  const target = (match2[1] ?? "").trim();
170522
170769
  if (!target) continue;
170523
170770
  if (target.includes("\n")) {
@@ -170552,14 +170799,14 @@ function extractImportEdges(projectId, file2, text, indexedAt) {
170552
170799
  function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
170553
170800
  const rel = normalizeCodePath(relative(projectRoot, abs));
170554
170801
  try {
170555
- const text = readFileSync7(abs, "utf-8");
170802
+ const text2 = readFileSync7(abs, "utf-8");
170556
170803
  const stat4 = fileStat ?? statSync4(abs);
170557
170804
  const file2 = {
170558
170805
  id: makeCodeFileId(projectId, rel),
170559
170806
  projectId,
170560
170807
  path: rel,
170561
170808
  language: languageForPath(rel),
170562
- contentHash: hashText(text),
170809
+ contentHash: hashText(text2),
170563
170810
  // Preserve filesystem precision. Rounding here made same-size edits in
170564
170811
  // a short Windows timestamp window indistinguishable to refresh.
170565
170812
  mtimeMs: Number(stat4.mtimeMs),
@@ -170569,8 +170816,8 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
170569
170816
  return {
170570
170817
  delta: {
170571
170818
  file: file2,
170572
- symbols: extractSymbols(projectId, file2, text, indexedAt),
170573
- edges: extractImportEdges(projectId, file2, text, indexedAt)
170819
+ symbols: extractSymbols(projectId, file2, text2, indexedAt),
170820
+ edges: extractImportEdges(projectId, file2, text2, indexedAt)
170574
170821
  },
170575
170822
  unreadable: false
170576
170823
  };
@@ -170849,18 +171096,18 @@ __export(binder_exports, {
170849
171096
  function observationText(obs) {
170850
171097
  return [obs.title, obs.narrative, ...obs.facts ?? []].join("\n");
170851
171098
  }
170852
- function mentionsSymbol(text, symbol2) {
171099
+ function mentionsSymbol(text2, symbol2) {
170853
171100
  const name = symbol2.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
170854
- return new RegExp(`(^|[^\\w$])${name}([^\\w$]|$)`).test(text);
171101
+ return new RegExp(`(^|[^\\w$])${name}([^\\w$]|$)`).test(text2);
170855
171102
  }
170856
- function identifierCandidates(text) {
170857
- return [...new Set(text.match(/[A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?/g) ?? [])];
171103
+ function identifierCandidates(text2) {
171104
+ return [...new Set(text2.match(/[A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?/g) ?? [])];
170858
171105
  }
170859
- function codeIdentifierCandidates(text) {
171106
+ function codeIdentifierCandidates(text2) {
170860
171107
  const explicit = /* @__PURE__ */ new Set();
170861
- for (const match2 of text.matchAll(/`([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)`/g)) explicit.add(match2[1]);
170862
- for (const match2 of text.matchAll(/\b([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)\s*\(/g)) explicit.add(match2[1]);
170863
- return identifierCandidates(text).filter((candidate2) => explicit.has(candidate2) || candidate2.includes("::") || /[!?=]$/.test(candidate2) || /^[A-Z]/.test(candidate2) || /[_$]/.test(candidate2) || /[a-z0-9][A-Z]/.test(candidate2) || /[A-Z]{2}/.test(candidate2));
171108
+ for (const match2 of text2.matchAll(/`([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)`/g)) explicit.add(match2[1]);
171109
+ for (const match2 of text2.matchAll(/\b([A-Za-z_$][\w$]*(?:::[A-Za-z_$][\w$]*)*[!?=]?)\s*\(/g)) explicit.add(match2[1]);
171110
+ return identifierCandidates(text2).filter((candidate2) => explicit.has(candidate2) || candidate2.includes("::") || /[!?=]$/.test(candidate2) || /^[A-Z]/.test(candidate2) || /[_$]/.test(candidate2) || /[a-z0-9][A-Z]/.test(candidate2) || /[A-Z]{2}/.test(candidate2));
170864
171111
  }
170865
171112
  function fileRef(projectId, obs, file2) {
170866
171113
  return {
@@ -170890,7 +171137,7 @@ function symbolRef(projectId, obs, file2, symbol2) {
170890
171137
  }
170891
171138
  function resolveObservationCodeRefs(obs, lookup2) {
170892
171139
  const refs = /* @__PURE__ */ new Map();
170893
- const text = observationText(obs);
171140
+ const text2 = observationText(obs);
170894
171141
  const candidateFiles = /* @__PURE__ */ new Map();
170895
171142
  for (const rawPath of obs.filesModified ?? []) {
170896
171143
  const file2 = lookup2.findFile(normalizeCodePath(rawPath));
@@ -170900,7 +171147,7 @@ function resolveObservationCodeRefs(obs, lookup2) {
170900
171147
  refs.set(ref.id, ref);
170901
171148
  }
170902
171149
  const hintedFileIds = new Set(candidateFiles.keys());
170903
- const symbolNames = hintedFileIds.size > 0 ? identifierCandidates(text) : codeIdentifierCandidates(text);
171150
+ const symbolNames = hintedFileIds.size > 0 ? identifierCandidates(text2) : codeIdentifierCandidates(text2);
170904
171151
  const symbols = lookup2.findSymbols(symbolNames, [...hintedFileIds]);
170905
171152
  const symbolsByName = /* @__PURE__ */ new Map();
170906
171153
  for (const symbol2 of symbols) {
@@ -170911,7 +171158,7 @@ function resolveObservationCodeRefs(obs, lookup2) {
170911
171158
  for (const group of symbolsByName.values()) {
170912
171159
  const candidates = group.length === 1 ? group : [];
170913
171160
  for (const symbol2 of candidates) {
170914
- if (!mentionsSymbol(text, symbol2)) continue;
171161
+ if (!mentionsSymbol(text2, symbol2)) continue;
170915
171162
  const file2 = candidateFiles.get(symbol2.fileId) ?? lookup2.findFile(symbol2.path);
170916
171163
  if (!file2) continue;
170917
171164
  candidateFiles.set(file2.id, file2);
@@ -171639,8 +171886,8 @@ function taskTokens(task) {
171639
171886
  return normalizedTokens(task);
171640
171887
  }
171641
171888
  function scoreClaim(claim, tokens) {
171642
- const text = [claim.subject, claim.predicate, claim.objectValue].join(" ").toLocaleLowerCase("en-US");
171643
- const words = normalizedTokens(text);
171889
+ const text2 = [claim.subject, claim.predicate, claim.objectValue].join(" ").toLocaleLowerCase("en-US");
171890
+ const words = normalizedTokens(text2);
171644
171891
  let matches = 0;
171645
171892
  for (const token of tokens) {
171646
171893
  if (words.has(token)) matches += 1;
@@ -176073,6 +176320,128 @@ var init_workflow_store = __esm({
176073
176320
  }
176074
176321
  });
176075
176322
 
176323
+ // src/knowledge/outcome-types.ts
176324
+ function qualityFromOutcome(signal) {
176325
+ if (!signal) return void 0;
176326
+ if (signal.kind === "verification-failed" || signal.kind === "user-correction" || signal.kind === "source-changed" || signal.kind === "conflict-confirmed") {
176327
+ return "degraded";
176328
+ }
176329
+ if (signal.kind === "verification-passed" || signal.kind === "verified-reuse" || signal.kind === "user-pin") {
176330
+ return "verified";
176331
+ }
176332
+ return void 0;
176333
+ }
176334
+ var MEMORY_OUTCOME_CANDIDATE_KINDS, MEMORY_OUTCOME_SIGNAL_KINDS;
176335
+ var init_outcome_types = __esm({
176336
+ "src/knowledge/outcome-types.ts"() {
176337
+ "use strict";
176338
+ init_esm_shims();
176339
+ MEMORY_OUTCOME_CANDIDATE_KINDS = ["claim", "durable-memory", "workflow"];
176340
+ MEMORY_OUTCOME_SIGNAL_KINDS = [
176341
+ "verification-passed",
176342
+ "verification-failed",
176343
+ "verified-reuse",
176344
+ "user-pin",
176345
+ "user-correction",
176346
+ "source-changed",
176347
+ "conflict-confirmed",
176348
+ "manual-review"
176349
+ ];
176350
+ }
176351
+ });
176352
+
176353
+ // src/knowledge/outcome-store.ts
176354
+ import { randomUUID as randomUUID10 } from "crypto";
176355
+ function optionalText4(value) {
176356
+ return typeof value === "string" && value.trim() ? value : void 0;
176357
+ }
176358
+ function text(value, field, max = 1e3) {
176359
+ const safe = sanitizeCredentials(value).replace(/\s+/g, " ").trim();
176360
+ if (!safe) throw new Error("Outcome signal " + field + " is required.");
176361
+ if (safe.length > max) throw new Error("Outcome signal " + field + " is too long.");
176362
+ return safe;
176363
+ }
176364
+ function oneOf(value, values, field) {
176365
+ if (typeof value !== "string" || !values.includes(value)) {
176366
+ throw new Error("Outcome signal " + field + " is invalid.");
176367
+ }
176368
+ return value;
176369
+ }
176370
+ function rowToSignal(row) {
176371
+ return {
176372
+ id: row.id,
176373
+ projectId: row.projectId,
176374
+ candidateKind: row.candidateKind,
176375
+ candidateId: row.candidateId,
176376
+ kind: row.kind,
176377
+ sourceRef: row.sourceRef,
176378
+ ...optionalText4(row.snapshotId) ? { snapshotId: row.snapshotId } : {},
176379
+ ...optionalText4(row.detail) ? { detail: row.detail } : {},
176380
+ observedAt: row.observedAt
176381
+ };
176382
+ }
176383
+ var OutcomeStore;
176384
+ var init_outcome_store = __esm({
176385
+ "src/knowledge/outcome-store.ts"() {
176386
+ "use strict";
176387
+ init_esm_shims();
176388
+ init_secret_filter();
176389
+ init_sqlite_db();
176390
+ init_outcome_types();
176391
+ OutcomeStore = class {
176392
+ db = null;
176393
+ async init(dataDir) {
176394
+ this.db = getDatabase(dataDir);
176395
+ }
176396
+ record(input) {
176397
+ const signal = {
176398
+ id: randomUUID10(),
176399
+ projectId: text(input.projectId, "project id"),
176400
+ candidateKind: oneOf(input.candidateKind, MEMORY_OUTCOME_CANDIDATE_KINDS, "candidate kind"),
176401
+ candidateId: text(input.candidateId, "candidate id"),
176402
+ kind: oneOf(input.kind, MEMORY_OUTCOME_SIGNAL_KINDS, "kind"),
176403
+ sourceRef: text(input.sourceRef, "source reference"),
176404
+ ...input.snapshotId ? { snapshotId: text(input.snapshotId, "snapshot id") } : {},
176405
+ ...input.detail ? { detail: text(input.detail, "detail") } : {},
176406
+ observedAt: input.observedAt ?? (/* @__PURE__ */ new Date()).toISOString()
176407
+ };
176408
+ this.db.prepare(`
176409
+ INSERT INTO memory_outcome_signals (
176410
+ id, projectId, candidateKind, candidateId, kind, sourceRef, snapshotId, detail, observedAt
176411
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
176412
+ `).run(
176413
+ signal.id,
176414
+ signal.projectId,
176415
+ signal.candidateKind,
176416
+ signal.candidateId,
176417
+ signal.kind,
176418
+ signal.sourceRef,
176419
+ signal.snapshotId ?? null,
176420
+ signal.detail ?? null,
176421
+ signal.observedAt
176422
+ );
176423
+ return signal;
176424
+ }
176425
+ latestForCandidates(projectId, candidateKind, candidateIds) {
176426
+ const ids = [...new Set(candidateIds.filter(Boolean))];
176427
+ if (ids.length === 0) return /* @__PURE__ */ new Map();
176428
+ const placeholders = ids.map(() => "?").join(", ");
176429
+ const rows = this.db.prepare(`
176430
+ SELECT * FROM memory_outcome_signals
176431
+ WHERE projectId = ? AND candidateKind = ? AND candidateId IN (${placeholders})
176432
+ ORDER BY observedAt DESC, id DESC
176433
+ `).all(projectId, candidateKind, ...ids);
176434
+ const latest = /* @__PURE__ */ new Map();
176435
+ for (const row of rows) {
176436
+ const signal = rowToSignal(row);
176437
+ if (!latest.has(signal.candidateId)) latest.set(signal.candidateId, signal);
176438
+ }
176439
+ return latest;
176440
+ }
176441
+ };
176442
+ }
176443
+ });
176444
+
176076
176445
  // src/codegraph/task-lens.ts
176077
176446
  var task_lens_exports = {};
176078
176447
  __export(task_lens_exports, {
@@ -176089,31 +176458,31 @@ __export(task_lens_exports, {
176089
176458
  function normalizePath2(path46) {
176090
176459
  return path46.replace(/\\/g, "/");
176091
176460
  }
176092
- function tokenize4(text) {
176093
- return (text.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
176461
+ function tokenize4(text2) {
176462
+ return (text2.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1 && !STOP_WORDS.has(token));
176094
176463
  }
176095
- function containsTaskKeyword(text, keyword) {
176464
+ function containsTaskKeyword(text2, keyword) {
176096
176465
  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");
176097
176466
  let match2;
176098
- while ((match2 = matcher.exec(text)) !== null) {
176467
+ while ((match2 = matcher.exec(text2)) !== null) {
176099
176468
  const keywordIndex = match2.index + (match2[1]?.length ?? 0);
176100
- if (!isNegatedTaskKeyword(text, keywordIndex)) return true;
176469
+ if (!isNegatedTaskKeyword(text2, keywordIndex)) return true;
176101
176470
  }
176102
176471
  return false;
176103
176472
  }
176104
- function isNegatedTaskKeyword(text, keywordIndex) {
176473
+ function isNegatedTaskKeyword(text2, keywordIndex) {
176105
176474
  const boundary = Math.max(
176106
- text.lastIndexOf(".", keywordIndex - 1),
176107
- text.lastIndexOf("!", keywordIndex - 1),
176108
- text.lastIndexOf("?", keywordIndex - 1),
176109
- text.lastIndexOf(";", keywordIndex - 1),
176110
- text.lastIndexOf("\n", keywordIndex - 1),
176111
- text.lastIndexOf("\u3002", keywordIndex - 1),
176112
- text.lastIndexOf("\uFF01", keywordIndex - 1),
176113
- text.lastIndexOf("\uFF1F", keywordIndex - 1),
176114
- text.lastIndexOf("\uFF1B", keywordIndex - 1)
176475
+ text2.lastIndexOf(".", keywordIndex - 1),
176476
+ text2.lastIndexOf("!", keywordIndex - 1),
176477
+ text2.lastIndexOf("?", keywordIndex - 1),
176478
+ text2.lastIndexOf(";", keywordIndex - 1),
176479
+ text2.lastIndexOf("\n", keywordIndex - 1),
176480
+ text2.lastIndexOf("\u3002", keywordIndex - 1),
176481
+ text2.lastIndexOf("\uFF01", keywordIndex - 1),
176482
+ text2.lastIndexOf("\uFF1F", keywordIndex - 1),
176483
+ text2.lastIndexOf("\uFF1B", keywordIndex - 1)
176115
176484
  );
176116
- let prefix = text.slice(boundary + 1, keywordIndex).toLowerCase();
176485
+ let prefix = text2.slice(boundary + 1, keywordIndex).toLowerCase();
176117
176486
  const contrast = /(?:,|\uff0c)\s*(?:but|however|instead|yet|\u4f46\u662f|\u4f46|\u800c\u662f)\s*/gi;
176118
176487
  let contrastMatch;
176119
176488
  let contrastEnd = -1;
@@ -176136,9 +176505,9 @@ function resolveTaskLens(task) {
176136
176505
  };
176137
176506
  for (const id of LENS_PRIORITY) {
176138
176507
  const score = KEYWORDS[id].reduce((sum, keyword) => sum + (containsTaskKeyword(normalized, keyword) ? 1 : 0), 0);
176139
- const priority = LENS_PRIORITY.indexOf(id);
176140
- if (score > best.score || score === best.score && score > 0 && priority < best.priority) {
176141
- best = { id, score, priority };
176508
+ const priority2 = LENS_PRIORITY.indexOf(id);
176509
+ if (score > best.score || score === best.score && score > 0 && priority2 < best.priority) {
176510
+ best = { id, score, priority: priority2 };
176142
176511
  }
176143
176512
  }
176144
176513
  return best.score > 0 ? LENSES[best.id] : LENSES.general;
@@ -176180,20 +176549,20 @@ function pathKindScore(path46, lens) {
176180
176549
  return 0;
176181
176550
  }
176182
176551
  }
176183
- function tokenScore(text, tokens) {
176552
+ function tokenScore(text2, tokens) {
176184
176553
  if (tokens.length === 0) return 0;
176185
- const normalized = text.toLowerCase();
176554
+ const normalized = text2.toLowerCase();
176186
176555
  return tokens.reduce((sum, token) => sum + (normalized.includes(token) ? 12 : 0), 0);
176187
176556
  }
176188
176557
  function sourceTaskMatchScore(source, task) {
176189
176558
  const tokens = tokenize4(task ?? "");
176190
176559
  if (tokens.length === 0) return 0;
176191
- const text = [
176560
+ const text2 = [
176192
176561
  source.title,
176193
176562
  source.path ?? "",
176194
176563
  source.symbol ?? ""
176195
176564
  ].join("\n").toLowerCase();
176196
- const matches = tokens.filter((token) => text.includes(token)).length;
176565
+ const matches = tokens.filter((token) => text2.includes(token)).length;
176197
176566
  if (matches >= 2) return 40;
176198
176567
  if (matches === 1) return 24;
176199
176568
  return 0;
@@ -176232,8 +176601,8 @@ function lensPathCandidates(lens) {
176232
176601
  }
176233
176602
  function scoreLensSource(source, lens, task) {
176234
176603
  const tokens = tokenize4(task ?? "");
176235
- const text = [source.title, source.type, source.path ?? "", source.symbol ?? ""].join("\n");
176236
- return pathKindScore(source.path ?? "", lens) + tokenScore(text, tokens) + sourceTaskMatchScore(source, task);
176604
+ const text2 = [source.title, source.type, source.path ?? "", source.symbol ?? ""].join("\n");
176605
+ return pathKindScore(source.path ?? "", lens) + tokenScore(text2, tokens) + sourceTaskMatchScore(source, task);
176237
176606
  }
176238
176607
  function rankLensSources(sources, lens, task) {
176239
176608
  return [...sources].map((source, index) => ({
@@ -176475,7 +176844,7 @@ function requiredText(data, key) {
176475
176844
  }
176476
176845
  return value.trim();
176477
176846
  }
176478
- function optionalText4(data, key) {
176847
+ function optionalText5(data, key) {
176479
176848
  const value = data[key];
176480
176849
  if (value === void 0 || value === null || value === "") return void 0;
176481
176850
  if (typeof value !== "string") throw new Error("workflow frontmatter field " + key + " must be text");
@@ -176518,11 +176887,11 @@ function phaseFromValue(value, index) {
176518
176887
  }
176519
176888
  const data = value;
176520
176889
  const title = requiredText(data, "title");
176521
- const phaseId = optionalText4(data, "id") ?? slug(title) + "-" + (index + 1);
176890
+ const phaseId = optionalText5(data, "id") ?? slug(title) + "-" + (index + 1);
176522
176891
  return {
176523
176892
  id: phaseId,
176524
176893
  title,
176525
- instructions: optionalText4(data, "instructions") ?? "",
176894
+ instructions: optionalText5(data, "instructions") ?? "",
176526
176895
  branches: optionalStringArray(data, "branches"),
176527
176896
  expectedOutputs: optionalStringArray(data, "expectedOutputs"),
176528
176897
  verificationGates: optionalStringArray(data, "verificationGates")
@@ -176631,7 +177000,7 @@ function parsedWorkflow(data, body, input) {
176631
177000
  id: requiredText(data, "id"),
176632
177001
  workspaceId: input.workspaceId,
176633
177002
  title: requiredText(data, "title"),
176634
- description: optionalText4(data, "description") ?? "",
177003
+ description: optionalText5(data, "description") ?? "",
176635
177004
  status: optionalStatus(data),
176636
177005
  version: optionalNumber(data, "version", 1),
176637
177006
  taskLenses: optionalStringArray(data, "taskLenses"),
@@ -176650,9 +177019,9 @@ function parsedWorkflow(data, body, input) {
176650
177019
  sourcePath: normalizeSourcePath(input.sourcePath),
176651
177020
  sourceHash: "",
176652
177021
  contentHash: input.contentHash,
176653
- createdAt: optionalText4(data, "createdAt") ?? now2(),
176654
- updatedAt: optionalText4(data, "updatedAt") ?? now2(),
176655
- ...optionalText4(data, "importedFrom") ? { importedFrom: optionalText4(data, "importedFrom") } : {}
177022
+ createdAt: optionalText5(data, "createdAt") ?? now2(),
177023
+ updatedAt: optionalText5(data, "updatedAt") ?? now2(),
177024
+ ...optionalText5(data, "importedFrom") ? { importedFrom: optionalText5(data, "importedFrom") } : {}
176656
177025
  };
176657
177026
  if (candidate2.phases.length === 0) {
176658
177027
  throw new Error("workflow must contain at least one phase or a non-empty body");
@@ -176751,11 +177120,11 @@ async function syncCanonicalWorkflows(workspace) {
176751
177120
  return { workflows, errors: errors2 };
176752
177121
  }
176753
177122
  function inferTaskLenses(value) {
176754
- const text = value.toLowerCase();
176755
- return Object.entries(LENS_TERMS).filter(([, terms]) => terms.some((term) => text.includes(term))).map(([lens]) => lens);
177123
+ const text2 = value.toLowerCase();
177124
+ return Object.entries(LENS_TERMS).filter(([, terms]) => terms.some((term) => text2.includes(term))).map(([lens]) => lens);
176756
177125
  }
176757
177126
  function taskScore(workflow, task) {
176758
- const text = task.toLowerCase();
177127
+ const text2 = task.toLowerCase();
176759
177128
  let score = 0;
176760
177129
  const reasons = [];
176761
177130
  const matchedLenses = /* @__PURE__ */ new Set();
@@ -177022,7 +177391,31 @@ async function recordWorkflowRun(input) {
177022
177391
  throw new Error("Workflow was not found for this workspace");
177023
177392
  }
177024
177393
  if (!input.run.task.trim()) throw new Error("Workflow run task is required");
177025
- return store2.recordRun(input.run);
177394
+ const run = store2.recordRun(input.run);
177395
+ const kind = run.outcome === "passed" && run.verificationVerdict === "passed" ? "verification-passed" : run.outcome === "failed" || run.verificationVerdict === "failed" ? "verification-failed" : void 0;
177396
+ if (!kind) return run;
177397
+ const evidence = /* @__PURE__ */ new Map();
177398
+ evidence.set(workflow.id, "workflow");
177399
+ for (const reference of run.selectedEvidence) {
177400
+ const match2 = /^(claim|durable):(.+)$/.exec(reference);
177401
+ if (!match2) continue;
177402
+ evidence.set(match2[2], match2[1] === "claim" ? "claim" : "durable-memory");
177403
+ }
177404
+ const outcomes = new OutcomeStore();
177405
+ await outcomes.init(workflowStoreDataDir(input.workspace));
177406
+ for (const [candidateId, candidateKind] of evidence) {
177407
+ outcomes.record({
177408
+ projectId: run.projectId,
177409
+ candidateKind,
177410
+ candidateId,
177411
+ kind,
177412
+ sourceRef: "workflow-run:" + run.id,
177413
+ ...run.startingSnapshotId ? { snapshotId: run.startingSnapshotId } : {},
177414
+ ...run.failureReason ? { detail: run.failureReason } : {},
177415
+ observedAt: run.completedAt ?? run.startedAt
177416
+ });
177417
+ }
177418
+ return run;
177026
177419
  }
177027
177420
  async function selectWorkspaceWorkflows(input) {
177028
177421
  const synced = await syncCanonicalWorkflows(input.workspace);
@@ -177048,6 +177441,7 @@ var init_workflows2 = __esm({
177048
177441
  init_workflow_sync();
177049
177442
  init_workspace();
177050
177443
  init_workflow_store();
177444
+ init_outcome_store();
177051
177445
  init_task_lens();
177052
177446
  KNOWN_AGENTS = [
177053
177447
  "windsurf",
@@ -178941,10 +179335,10 @@ function isEmbeddingEnabled() {
178941
179335
  function getVectorDimensions() {
178942
179336
  return embeddingEnabled ? embeddingDimensions : null;
178943
179337
  }
178944
- async function generateEmbedding(text) {
179338
+ async function generateEmbedding(text2) {
178945
179339
  const provider2 = await getEmbeddingProvider();
178946
179340
  if (!provider2) return null;
178947
- return provider2.embedInput ? provider2.embedInput({ modality: "text", text }, { intent: "document" }) : provider2.embed(text);
179341
+ return provider2.embedInput ? provider2.embedInput({ modality: "text", text: text2 }, { intent: "document" }) : provider2.embed(text2);
178948
179342
  }
178949
179343
  async function generateEmbeddingInput(input, options2 = {}) {
178950
179344
  const provider2 = await getEmbeddingProvider();
@@ -180391,7 +180785,7 @@ __export(team_store_exports, {
180391
180785
  isTeamStoreInitialized: () => isTeamStoreInitialized,
180392
180786
  resetTeamStore: () => resetTeamStore
180393
180787
  });
180394
- import { randomUUID as randomUUID10 } from "crypto";
180788
+ import { randomUUID as randomUUID11 } from "crypto";
180395
180789
  import path21 from "path";
180396
180790
  import fs14 from "fs";
180397
180791
  function getTeamStore() {
@@ -180680,7 +181074,7 @@ var init_team_store = __esm({
180680
181074
  * reactivate it (preserving agent_id). Otherwise create a new one.
180681
181075
  */
180682
181076
  registerAgent(input) {
180683
- const instanceId = input.instanceId || randomUUID10();
181077
+ const instanceId = input.instanceId || randomUUID11();
180684
181078
  const now3 = Date.now();
180685
181079
  const existing = this.stmtAgentFindByInstance.get(
180686
181080
  input.projectId,
@@ -180706,7 +181100,7 @@ var init_team_store = __esm({
180706
181100
  this.eventBus?.emit("agent:joined", { agentId: row2.agent_id, projectId: input.projectId, agentType: input.agentType });
180707
181101
  return row2;
180708
181102
  }
180709
- const agentId = randomUUID10();
181103
+ const agentId = randomUUID11();
180710
181104
  this.stmtAgentUpsert.run({
180711
181105
  agent_id: agentId,
180712
181106
  project_id: input.projectId,
@@ -180808,7 +181202,7 @@ var init_team_store = __esm({
180808
181202
  return { error: `Recipient agent '${input.recipientAgentId}' not found \u2014 cannot send to unknown agent` };
180809
181203
  }
180810
181204
  }
180811
- const id = randomUUID10();
181205
+ const id = randomUUID11();
180812
181206
  const now3 = Date.now();
180813
181207
  const row = {
180814
181208
  id,
@@ -180858,7 +181252,7 @@ var init_team_store = __esm({
180858
181252
  // Task Operations (with atomic claim semantics)
180859
181253
  // ═══════════════════════════════════════════════════════════════════
180860
181254
  createTask(input) {
180861
- const taskId = randomUUID10();
181255
+ const taskId = randomUUID11();
180862
181256
  const now3 = Date.now();
180863
181257
  const row = {
180864
181258
  task_id: taskId,
@@ -181130,7 +181524,7 @@ var init_team_store = __esm({
181130
181524
  for (const [agentId, msgs] of Object.entries(snap.messages.inboxes)) {
181131
181525
  for (const msg of msgs) {
181132
181526
  this.stmtMsgInsert.run({
181133
- id: msg.id ?? randomUUID10(),
181527
+ id: msg.id ?? randomUUID11(),
181134
181528
  project_id: "migrated",
181135
181529
  sender_agent_id: msg.from ?? "unknown",
181136
181530
  recipient_agent_id: msg.to === "__broadcast__" ? null : msg.to ?? agentId,
@@ -181492,9 +181886,9 @@ __export(chat_service_exports, {
181492
181886
  askMemoryQuestion: () => askMemoryQuestion,
181493
181887
  askMemoryQuestionStream: () => askMemoryQuestionStream
181494
181888
  });
181495
- function truncate(text, max) {
181496
- if (text.length <= max) return text;
181497
- return `${text.slice(0, max - 1)}\u2026`;
181889
+ function truncate(text2, max) {
181890
+ if (text2.length <= max) return text2;
181891
+ return `${text2.slice(0, max - 1)}\u2026`;
181498
181892
  }
181499
181893
  function buildExcerpt(doc) {
181500
181894
  const combined = [doc.narrative, doc.facts].filter(Boolean).join(" ").replace(/\s+/g, " ").trim();
@@ -182299,7 +182693,7 @@ function evidenceScore2(obs) {
182299
182693
  }
182300
182694
  function scoreForPacket(obs, queryTokens, referenceTime, broadMemoryQuery) {
182301
182695
  let score = 0;
182302
- const text = normalizeText3([
182696
+ const text2 = normalizeText3([
182303
182697
  obs.title,
182304
182698
  obs.narrative,
182305
182699
  obs.entityName,
@@ -182308,15 +182702,15 @@ function scoreForPacket(obs, queryTokens, referenceTime, broadMemoryQuery) {
182308
182702
  ...obs.relatedEntities ?? [],
182309
182703
  ...obs.relatedCommits ?? []
182310
182704
  ].join(" "));
182311
- const matchingTokens = queryTokens.filter((token) => text.includes(token));
182705
+ const matchingTokens = queryTokens.filter((token) => text2.includes(token));
182312
182706
  score += matchingTokens.length * 4;
182313
182707
  if (queryTokens.length > 0 && matchingTokens.length === 0) {
182314
182708
  score -= 8;
182315
182709
  }
182316
- if (broadMemoryQuery && /memorix|memcode|memory-(?:graph|injection|runtime|quality|formation)|graph-context/.test(text)) {
182710
+ if (broadMemoryQuery && /memorix|memcode|memory-(?:graph|injection|runtime|quality|formation)|graph-context/.test(text2)) {
182317
182711
  score += 8;
182318
182712
  }
182319
- if (/\bmemory[- ]?game\b|e2e-test\/memory-game|team-handoff/.test(text)) {
182713
+ if (/\bmemory[- ]?game\b|e2e-test\/memory-game|team-handoff/.test(text2)) {
182320
182714
  score -= broadMemoryQuery ? 12 : 4;
182321
182715
  }
182322
182716
  score += obs.valueCategory === "core" ? 6 : 0;
@@ -182784,8 +183178,8 @@ async function getCliProjectContext(options2) {
182784
183178
  ...identity.warning ? { identityWarning: identity.warning } : {}
182785
183179
  };
182786
183180
  }
182787
- function emitResult(data, text, asJson) {
182788
- console.log(asJson ? JSON.stringify(data, null, 2) : text);
183181
+ function emitResult(data, text2, asJson) {
183182
+ console.log(asJson ? JSON.stringify(data, null, 2) : text2);
182789
183183
  }
182790
183184
  function emitError(message, asJson) {
182791
183185
  console.error(asJson ? JSON.stringify({ error: message }, null, 2) : `Error: ${message}`);
@@ -182913,7 +183307,7 @@ var owner_exports = {};
182913
183307
  __export(owner_exports, {
182914
183308
  resolveLocalMemoryOwner: () => resolveLocalMemoryOwner
182915
183309
  });
182916
- import { randomUUID as randomUUID11 } from "crypto";
183310
+ import { randomUUID as randomUUID12 } from "crypto";
182917
183311
  import { promises as fs17 } from "fs";
182918
183312
  import path24 from "path";
182919
183313
  function ownerPath(dataDir) {
@@ -182943,7 +183337,7 @@ async function resolveLocalMemoryOwner(dataDir, options2 = {}) {
182943
183337
  await fs17.mkdir(path24.dirname(filePath), { recursive: true });
182944
183338
  const created = {
182945
183339
  version: 1,
182946
- id: "local-" + randomUUID11(),
183340
+ id: "local-" + randomUUID12(),
182947
183341
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
182948
183342
  };
182949
183343
  try {
@@ -182966,8 +183360,8 @@ var init_owner = __esm({
182966
183360
  });
182967
183361
 
182968
183362
  // src/memory/long-term-store.ts
182969
- import { randomUUID as randomUUID12 } from "crypto";
182970
- function optionalText5(value) {
183363
+ import { randomUUID as randomUUID13 } from "crypto";
183364
+ function optionalText6(value) {
182971
183365
  return typeof value === "string" && value.trim() ? value : void 0;
182972
183366
  }
182973
183367
  function arrayValue2(value) {
@@ -182992,17 +183386,17 @@ function rowToMemory(row) {
182992
183386
  content: row.content,
182993
183387
  facts: arrayValue2(row.factsJson),
182994
183388
  tags: arrayValue2(row.tagsJson),
182995
- ...optionalText5(row.applicability) ? { applicability: row.applicability } : {},
183389
+ ...optionalText6(row.applicability) ? { applicability: row.applicability } : {},
182996
183390
  origin: row.origin,
182997
183391
  createdAt: row.createdAt,
182998
183392
  updatedAt: row.updatedAt,
182999
- ...optionalText5(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
183000
- ...optionalText5(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
183001
- ...optionalText5(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
183002
- ...optionalText5(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
183003
- ...optionalText5(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
183393
+ ...optionalText6(row.qualifiedAt) ? { qualifiedAt: row.qualifiedAt } : {},
183394
+ ...optionalText6(row.approvedAt) ? { approvedAt: row.approvedAt } : {},
183395
+ ...optionalText6(row.archivedAt) ? { archivedAt: row.archivedAt } : {},
183396
+ ...optionalText6(row.supersededBy) ? { supersededBy: row.supersededBy } : {},
183397
+ ...optionalText6(row.lastValidatedAt) ? { lastValidatedAt: row.lastValidatedAt } : {},
183004
183398
  accessCount: Number(row.accessCount ?? 0),
183005
- ...optionalText5(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
183399
+ ...optionalText6(row.lastAccessedAt) ? { lastAccessedAt: row.lastAccessedAt } : {}
183006
183400
  };
183007
183401
  }
183008
183402
  function rowToEvidence2(row) {
@@ -183012,8 +183406,8 @@ function rowToEvidence2(row) {
183012
183406
  kind: row.kind,
183013
183407
  referenceId: row.referenceId,
183014
183408
  relation: row.relation,
183015
- ...optionalText5(row.locator) ? { locator: row.locator } : {},
183016
- ...optionalText5(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
183409
+ ...optionalText6(row.locator) ? { locator: row.locator } : {},
183410
+ ...optionalText6(row.capturedHash) ? { capturedHash: row.capturedHash } : {},
183017
183411
  createdAt: row.createdAt
183018
183412
  };
183019
183413
  }
@@ -183022,9 +183416,9 @@ function rowToEvent2(row) {
183022
183416
  id: row.id,
183023
183417
  memoryId: row.memoryId,
183024
183418
  kind: row.kind,
183025
- ...optionalText5(row.fromState) ? { fromState: row.fromState } : {},
183026
- ...optionalText5(row.toState) ? { toState: row.toState } : {},
183027
- ...optionalText5(row.detail) ? { detail: row.detail } : {},
183419
+ ...optionalText6(row.fromState) ? { fromState: row.fromState } : {},
183420
+ ...optionalText6(row.toState) ? { toState: row.toState } : {},
183421
+ ...optionalText6(row.detail) ? { detail: row.detail } : {},
183028
183422
  createdAt: row.createdAt
183029
183423
  };
183030
183424
  }
@@ -183126,7 +183520,7 @@ var init_long_term_store = __esm({
183126
183520
  }
183127
183521
  insertEvidence(input) {
183128
183522
  const evidence = {
183129
- id: randomUUID12(),
183523
+ id: randomUUID13(),
183130
183524
  ...input,
183131
183525
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
183132
183526
  };
@@ -183153,7 +183547,7 @@ var init_long_term_store = __esm({
183153
183547
  }
183154
183548
  recordEvent(input) {
183155
183549
  const event = {
183156
- id: randomUUID12(),
183550
+ id: randomUUID13(),
183157
183551
  ...input,
183158
183552
  createdAt: input.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
183159
183553
  };
@@ -183241,7 +183635,7 @@ __export(long_term_exports, {
183241
183635
  selectLongTermMemoriesForTask: () => selectLongTermMemoriesForTask,
183242
183636
  supersedeLongTermMemory: () => supersedeLongTermMemory
183243
183637
  });
183244
- import { randomUUID as randomUUID13 } from "crypto";
183638
+ import { randomUUID as randomUUID14 } from "crypto";
183245
183639
  function isOneOf(value, values) {
183246
183640
  return typeof value === "string" && values.includes(value);
183247
183641
  }
@@ -183423,7 +183817,7 @@ async function createManualLongTermMemory(input) {
183423
183817
  const owner = await resolveLocalMemoryOwner(input.dataDir, { create: true });
183424
183818
  if (!owner) throw new Error("Memorix could not resolve a local memory owner.");
183425
183819
  assertScope(input.scope);
183426
- const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID13(), relation: "supports" }];
183820
+ const evidence = input.scope === "user" ? [{ kind: "user", referenceId: owner.id, relation: "user-confirmed" }] : [{ kind: "manual", referenceId: "manual:" + randomUUID14(), relation: "supports" }];
183427
183821
  return createLongTermMemoryWithDataDir({
183428
183822
  dataDir: input.dataDir,
183429
183823
  originProjectId: input.projectId,
@@ -183478,7 +183872,7 @@ async function createLongTermMemoryWithDataDir(input) {
183478
183872
  assertPortableEvidence(input.scope, portability, evidenceInputs);
183479
183873
  const now3 = (/* @__PURE__ */ new Date()).toISOString();
183480
183874
  const memory = {
183481
- id: randomUUID13(),
183875
+ id: randomUUID14(),
183482
183876
  originProjectId: compactText2(input.originProjectId, "origin project id", 1e3),
183483
183877
  ownerId: compactText2(input.ownerId, "owner id", 160),
183484
183878
  scope: input.scope,
@@ -188931,12 +189325,99 @@ var init_integrate = __esm({
188931
189325
  }
188932
189326
  });
188933
189327
 
189328
+ // src/knowledge/governor.ts
189329
+ function clampRelevance(value) {
189330
+ if (!Number.isFinite(value)) return 0;
189331
+ return Math.max(0, Math.min(1, value));
189332
+ }
189333
+ function classify(candidate2) {
189334
+ const freshness = candidate2.freshness ?? "unknown";
189335
+ const trust = candidate2.trust ?? "historical";
189336
+ const quality = candidate2.quality ?? "probationary";
189337
+ const conflict = candidate2.conflict ?? "none";
189338
+ if (!candidate2.scopeAllowed) {
189339
+ return { disposition: "exclude", reasons: ["scope-forbidden"] };
189340
+ }
189341
+ if (conflict === "confirmed") {
189342
+ return { disposition: "exclude", reasons: ["confirmed-conflict"] };
189343
+ }
189344
+ if (quality === "blocked") {
189345
+ return { disposition: "exclude", reasons: ["blocked-quality"] };
189346
+ }
189347
+ if (quality === "degraded") {
189348
+ return { disposition: "defer", reasons: ["degraded-quality"] };
189349
+ }
189350
+ if (freshness === "stale") {
189351
+ return { disposition: "defer", reasons: ["stale-evidence"] };
189352
+ }
189353
+ const reasons = [];
189354
+ let disposition = "include";
189355
+ if (freshness === "unknown") {
189356
+ disposition = "compact";
189357
+ reasons.push("unknown-freshness");
189358
+ }
189359
+ if (conflict === "possible") {
189360
+ disposition = "compact";
189361
+ reasons.push("possible-conflict");
189362
+ }
189363
+ if (quality === "probationary") {
189364
+ disposition = "compact";
189365
+ reasons.push("probationary-evidence");
189366
+ }
189367
+ if (disposition === "include" && freshness === "current" && trust === "source-backed") {
189368
+ reasons.push("current-source-backed-evidence");
189369
+ } else if (reasons.length === 0) {
189370
+ reasons.push("relevant-evidence");
189371
+ }
189372
+ return { disposition, reasons };
189373
+ }
189374
+ function priority(decision) {
189375
+ const dispositionWeight = {
189376
+ include: 3,
189377
+ compact: 2,
189378
+ defer: 1,
189379
+ exclude: 0
189380
+ };
189381
+ const evidence = Math.min(3, decision.candidate.evidenceCount ?? 0) / 10;
189382
+ return dispositionWeight[decision.disposition] + clampRelevance(decision.candidate.relevance) + evidence;
189383
+ }
189384
+ function governContextCandidates(candidates, maxTokens) {
189385
+ const safeBudget = Math.max(0, Math.floor(maxTokens));
189386
+ const decisions = candidates.map((candidate2) => ({ candidate: candidate2, ...classify(candidate2) }));
189387
+ const eligible = decisions.filter((decision) => decision.disposition === "include" || decision.disposition === "compact").sort((left, right) => priority(right) - priority(left));
189388
+ let usedTokens = 0;
189389
+ for (const decision of eligible) {
189390
+ const tokens = Math.max(0, Math.ceil(decision.candidate.estimatedTokens));
189391
+ if (usedTokens + tokens <= safeBudget) {
189392
+ usedTokens += tokens;
189393
+ continue;
189394
+ }
189395
+ decision.disposition = "defer";
189396
+ decision.reasons = [...decision.reasons, "token-budget"];
189397
+ }
189398
+ const delivered = decisions.filter((decision) => decision.disposition === "include" || decision.disposition === "compact");
189399
+ const mode = delivered.length === 0 ? "abstain" : delivered.some((decision) => decision.disposition === "include") ? "workset" : "card";
189400
+ const cautions = [...new Set(decisions.filter((decision) => decision.disposition !== "include").flatMap((decision) => decision.reasons))];
189401
+ return {
189402
+ mode,
189403
+ budget: { maxTokens: safeBudget, usedTokens },
189404
+ decisions,
189405
+ cautions: cautions.length > 0 ? cautions : ["no-qualified-evidence"]
189406
+ };
189407
+ }
189408
+ var init_governor = __esm({
189409
+ "src/knowledge/governor.ts"() {
189410
+ "use strict";
189411
+ init_esm_shims();
189412
+ }
189413
+ });
189414
+
188934
189415
  // src/knowledge/workset.ts
188935
189416
  function unique(values) {
188936
189417
  return [...new Set(values.filter(Boolean))];
188937
189418
  }
188938
- function short(text, budget = 28) {
188939
- const safe = sanitizeCredentials(text).replace(/\s+/g, " ").trim();
189419
+ function short(text2, budget = 28) {
189420
+ const safe = sanitizeCredentials(text2).replace(/\s+/g, " ").trim();
188940
189421
  return countTextTokens(safe) <= budget ? safe : truncateToTokenBudget(safe, budget);
188941
189422
  }
188942
189423
  function claimAssertion(claim) {
@@ -189067,6 +189548,65 @@ function receiptOmissions(omitted, hiddenCautionMemoryCount) {
189067
189548
  function scheduledActions(cautions) {
189068
189549
  return cautions.filter((caution) => caution.kind === "codegraph-refresh-queued").map((caution) => short(caution.message, 28));
189069
189550
  }
189551
+ function isGovernedDelivery(disposition) {
189552
+ return disposition === "include" || disposition === "compact";
189553
+ }
189554
+ function governOptionalArtifacts(input) {
189555
+ const candidates = [
189556
+ ...input.reliableMemory.map((memory, index) => ({
189557
+ kind: "memory",
189558
+ id: "memory:" + memory.id,
189559
+ estimatedTokens: 10,
189560
+ relevance: Math.max(0.2, 0.9 - index * 0.1),
189561
+ scopeAllowed: true,
189562
+ freshness: freshnessForMemory(memory.status),
189563
+ trust: "historical",
189564
+ quality: memory.status === "current" ? "verified" : "degraded"
189565
+ })),
189566
+ ...input.claims.map((claim, index) => ({
189567
+ kind: "claim",
189568
+ id: "claim:" + claim.id,
189569
+ estimatedTokens: 12,
189570
+ relevance: Math.max(0.2, 0.95 - index * 0.1),
189571
+ scopeAllowed: true,
189572
+ freshness: claim.status === "active" ? "current" : "unknown",
189573
+ trust: "source-backed",
189574
+ quality: claim.reviewState === "approved" ? "verified" : "probationary",
189575
+ conflict: claim.status === "disputed" ? "confirmed" : "none",
189576
+ evidenceCount: claim.evidenceRefs.length
189577
+ })),
189578
+ ...input.durableMemory.map((memory, index) => ({
189579
+ kind: "durable-memory",
189580
+ id: "durable:" + memory.id,
189581
+ estimatedTokens: 14,
189582
+ relevance: Math.max(0.2, 0.8 - index * 0.1),
189583
+ scopeAllowed: true,
189584
+ freshness: memory.state === "approved" ? "current" : "unknown",
189585
+ trust: "source-backed",
189586
+ quality: memory.quality,
189587
+ evidenceCount: memory.evidenceRefs.length
189588
+ })),
189589
+ ...input.workflows.map((workflow, index) => ({
189590
+ kind: "workflow",
189591
+ id: "workflow:" + workflow.id,
189592
+ estimatedTokens: 14,
189593
+ relevance: Math.max(0.2, 0.85 - index * 0.1),
189594
+ scopeAllowed: true,
189595
+ freshness: "current",
189596
+ trust: "source-backed",
189597
+ quality: "verified"
189598
+ }))
189599
+ ];
189600
+ const plan = governContextCandidates(candidates, Number.MAX_SAFE_INTEGER);
189601
+ const permitted = new Set(plan.decisions.filter((decision) => isGovernedDelivery(decision.disposition)).map((decision) => decision.candidate.id));
189602
+ return {
189603
+ plan,
189604
+ reliableMemory: input.reliableMemory.filter((memory) => permitted.has("memory:" + memory.id)),
189605
+ claims: input.claims.filter((claim) => permitted.has("claim:" + claim.id)),
189606
+ durableMemory: input.durableMemory.filter((memory) => permitted.has("durable:" + memory.id)),
189607
+ workflows: input.workflows.filter((workflow) => permitted.has("workflow:" + workflow.id))
189608
+ };
189609
+ }
189070
189610
  function renderTaskWorksetPrompt(input) {
189071
189611
  const maxTokens = input.budget?.maxTokens ?? 180;
189072
189612
  const omitted = [];
@@ -189194,6 +189734,56 @@ function renderTaskWorksetPrompt(input) {
189194
189734
  trust: "source-backed"
189195
189735
  });
189196
189736
  }
189737
+ if (input.codeEvolution && input.codeEvolution.changes.length > 0) {
189738
+ appendLine(lines, "", maxTokens, omitted, "code-evolution-heading");
189739
+ appendLine(lines, "Code changes since prior scan", maxTokens, omitted, "code-evolution-heading");
189740
+ for (const change of input.codeEvolution.changes.slice(0, 3)) {
189741
+ appendLine(
189742
+ lines,
189743
+ "- " + change.kind + ": " + change.path,
189744
+ maxTokens,
189745
+ omitted,
189746
+ "code-evolution-change",
189747
+ selected,
189748
+ {
189749
+ kind: "code-state",
189750
+ id: "snapshot:" + input.codeEvolution.toSnapshotId,
189751
+ reason: "exact file hash change between complete CodeGraph snapshots",
189752
+ freshness: "current",
189753
+ trust: "source-backed"
189754
+ }
189755
+ );
189756
+ }
189757
+ for (const path46 of input.codeEvolution.directlyConnectedPaths.slice(0, 2)) {
189758
+ appendLine(
189759
+ lines,
189760
+ "- connected now: " + path46,
189761
+ maxTokens,
189762
+ omitted,
189763
+ "code-evolution-impact",
189764
+ selected,
189765
+ {
189766
+ kind: "code-state",
189767
+ id: "snapshot:" + input.codeEvolution.toSnapshotId,
189768
+ reason: "bounded current CodeGraph impact relation",
189769
+ freshness: "current",
189770
+ trust: "derived"
189771
+ }
189772
+ );
189773
+ }
189774
+ if ((input.codeEvolution.affectedMemoryCount ?? 0) > 0) {
189775
+ appendLine(
189776
+ lines,
189777
+ "- " + input.codeEvolution.affectedMemoryCount + " stored memory link(s) reference this changed code; reread source before relying on their conclusions.",
189778
+ maxTokens,
189779
+ omitted,
189780
+ "code-evolution-stale-memory"
189781
+ );
189782
+ }
189783
+ if (input.codeEvolution.truncated) {
189784
+ appendLine(lines, "- More connected files exist; inspect CodeGraph before assuming complete impact.", maxTokens, omitted, "code-evolution-truncated");
189785
+ }
189786
+ }
189197
189787
  if (input.semanticCode && (input.semanticCode.entryPoints.length > 0 || input.semanticCode.relations.length > 0)) {
189198
189788
  appendLine(lines, "", maxTokens, omitted, "semantic-code-heading");
189199
189789
  appendLine(lines, "Semantic code outline", maxTokens, omitted, "semantic-code-heading");
@@ -189384,6 +189974,17 @@ async function buildTaskWorkset(input) {
189384
189974
  }));
189385
189975
  let durableMemory = [];
189386
189976
  let durableEvidence = [];
189977
+ let outcomeStore;
189978
+ try {
189979
+ outcomeStore = new OutcomeStore();
189980
+ await outcomeStore.init(input.dataDir);
189981
+ } catch {
189982
+ }
189983
+ const claimQuality = outcomeStore ? outcomeStore.latestForCandidates(input.projectId, "claim", claims.map((claim) => claim.id)) : /* @__PURE__ */ new Map();
189984
+ for (const claim of claims) {
189985
+ const outcomeQuality = qualityFromOutcome(claimQuality.get(claim.id));
189986
+ if (outcomeQuality === "degraded") claim.reviewState = "needs-review";
189987
+ }
189387
189988
  if (task) {
189388
189989
  try {
189389
189990
  const selected = await selectLongTermMemoriesForTask({
@@ -189394,11 +189995,13 @@ async function buildTaskWorkset(input) {
189394
189995
  ...input.reader?.isTeamMember ? { isTeamMember: true } : {},
189395
189996
  limit: 3
189396
189997
  });
189998
+ const durableQuality = outcomeStore ? outcomeStore.latestForCandidates(input.projectId, "durable-memory", selected.map((item) => item.memory.id)) : /* @__PURE__ */ new Map();
189397
189999
  durableMemory = selected.map((item) => ({
189398
190000
  id: item.memory.id,
189399
190001
  kind: item.memory.kind,
189400
190002
  scope: item.memory.scope,
189401
190003
  state: item.memory.state,
190004
+ quality: qualityFromOutcome(durableQuality.get(item.memory.id)) ?? (item.memory.state === "approved" ? "verified" : "probationary"),
189402
190005
  title: item.memory.title,
189403
190006
  summary: renderLongTermMemorySummary(item.memory, 20),
189404
190007
  evidenceRefs: item.evidence.map((evidence) => evidence.id),
@@ -189444,18 +190047,25 @@ async function buildTaskWorkset(input) {
189444
190047
  }
189445
190048
  } catch {
189446
190049
  }
189447
- const evidenceIds = unique(selection.claims.flatMap((claim) => evidenceIdsForClaim(
189448
- claim,
189449
- evidenceByClaim.get(claim.id) ?? []
189450
- )).concat(
189451
- durableMemory.map((memory) => "durable:" + memory.id),
189452
- durableEvidence.map((evidence) => "durable-evidence:" + evidence.id)
189453
- ));
189454
190050
  const verification = unique([
189455
190051
  ...workflows.flatMap((workflow) => workflow.verificationGates),
189456
190052
  ...input.verificationHints
189457
190053
  ]).slice(0, 4);
189458
190054
  const normalizedCautions = unique(cautions.map((caution) => caution.kind)).map((kind) => cautions.find((caution) => caution.kind === kind)).slice(0, 6);
190055
+ const governed = governOptionalArtifacts({
190056
+ reliableMemory: input.reliableMemory?.slice(0, 3) ?? [],
190057
+ claims,
190058
+ durableMemory,
190059
+ workflows
190060
+ });
190061
+ const governedDurableIds = new Set(governed.durableMemory.map((memory) => memory.id));
190062
+ const evidenceIds = unique(governed.claims.flatMap((claim) => evidenceIdsForClaim(
190063
+ claim,
190064
+ evidenceByClaim.get(claim.id) ?? []
190065
+ )).concat(
190066
+ governed.durableMemory.map((memory) => "durable:" + memory.id),
190067
+ durableEvidence.filter((evidence) => governedDurableIds.has(evidence.memoryId)).map((evidence) => "durable-evidence:" + evidence.id)
190068
+ ));
189459
190069
  const continuation = input.continuation && (input.continuation.previousSession || input.continuation.memories.length > 0 || input.continuation.compactCheckpoint) ? {
189460
190070
  ...input.continuation.previousSession ? {
189461
190071
  previousSession: {
@@ -189482,15 +190092,16 @@ async function buildTaskWorkset(input) {
189482
190092
  currentFacts: input.currentFacts?.map((fact) => fact.startsWith("Historical note:") ? short(fact, 48) : short(fact, 28)).slice(0, 4) ?? [],
189483
190093
  ...continuation ? { continuation } : {},
189484
190094
  ...input.codeState ? { codeState: short(input.codeState, 28) } : {},
190095
+ ...input.codeEvolution ? { codeEvolution: input.codeEvolution } : {},
189485
190096
  startHere: unique(input.startHere).slice(0, 5),
189486
190097
  ...input.semanticCode ? { semanticCode: input.semanticCode } : {},
189487
- reliableMemory: input.reliableMemory?.slice(0, 3) ?? [],
190098
+ reliableMemory: governed.reliableMemory,
189488
190099
  cautionMemory: input.cautionMemory?.slice(0, 3) ?? [],
189489
190100
  hiddenCautionMemoryCount: input.hiddenCautionMemoryCount ?? 0,
189490
- claims,
189491
- pages,
189492
- durableMemory,
189493
- workflows,
190101
+ claims: governed.claims,
190102
+ pages: pages.filter((page) => page.claimIds.some((claimId) => governed.claims.some((claim) => claim.id === claimId))),
190103
+ durableMemory: governed.durableMemory,
190104
+ workflows: governed.workflows,
189494
190105
  cautions: normalizedCautions,
189495
190106
  verification,
189496
190107
  evidenceIds,
@@ -189515,6 +190126,17 @@ async function buildTaskWorkset(input) {
189515
190126
  },
189516
190127
  selected: rendered.selected,
189517
190128
  omitted: receiptOmissions(rendered.omittedItems, base.hiddenCautionMemoryCount),
190129
+ governance: {
190130
+ scope: "optional-evidence",
190131
+ mode: governed.plan.mode,
190132
+ decisions: governed.plan.decisions.map((decision) => ({
190133
+ kind: decision.candidate.kind,
190134
+ ...decision.candidate.id ? { id: decision.candidate.id } : {},
190135
+ disposition: decision.disposition,
190136
+ reasons: decision.reasons
190137
+ })),
190138
+ cautions: governed.plan.cautions
190139
+ },
189518
190140
  scheduledActions: scheduledActions(normalizedCautions)
189519
190141
  };
189520
190142
  return {
@@ -189540,8 +190162,11 @@ var init_workset = __esm({
189540
190162
  init_workspace_store();
189541
190163
  init_workspace();
189542
190164
  init_workflow_store();
190165
+ init_outcome_store();
190166
+ init_outcome_types();
189543
190167
  init_workflows2();
189544
190168
  init_long_term();
190169
+ init_governor();
189545
190170
  CONTINUATION_DETAIL_TOKEN_BUDGET = 20;
189546
190171
  }
189547
190172
  });
@@ -189564,19 +190189,19 @@ function readTextIfExists(filePath) {
189564
190189
  }
189565
190190
  }
189566
190191
  function readPackageVersion(rootPath) {
189567
- const text = readTextIfExists(path30.join(rootPath, "package.json"));
189568
- if (!text) return void 0;
190192
+ const text2 = readTextIfExists(path30.join(rootPath, "package.json"));
190193
+ if (!text2) return void 0;
189569
190194
  try {
189570
- const parsed = JSON.parse(text);
190195
+ const parsed = JSON.parse(text2);
189571
190196
  return typeof parsed.version === "string" ? parsed.version : void 0;
189572
190197
  } catch {
189573
190198
  return void 0;
189574
190199
  }
189575
190200
  }
189576
190201
  function readLatestChangelog(rootPath) {
189577
- const text = readTextIfExists(path30.join(rootPath, "CHANGELOG.md"));
189578
- if (!text) return void 0;
189579
- const match2 = text.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
190202
+ const text2 = readTextIfExists(path30.join(rootPath, "CHANGELOG.md"));
190203
+ if (!text2) return void 0;
190204
+ const match2 = text2.match(/^##\s+\[?v?([^\]\s]+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/m);
189580
190205
  if (!match2) return void 0;
189581
190206
  return {
189582
190207
  version: match2[1],
@@ -189639,6 +190264,7 @@ function compareDateStrings(a3, b3) {
189639
190264
  }
189640
190265
  function detectStaleProgressNotes(input) {
189641
190266
  const candidates = [
190267
+ "ACTIVE_WORK.md",
189642
190268
  "progress.txt",
189643
190269
  "docs/dev-log/progress.txt",
189644
190270
  "docs/memcode/dev-log/progress.txt"
@@ -189776,6 +190402,7 @@ function providerQuality(input) {
189776
190402
  capabilities: {
189777
190403
  declarations: true,
189778
190404
  importHints: true,
190405
+ localRelativeImportTargets: true,
189779
190406
  resolvedRelations: false,
189780
190407
  exactLocations: false
189781
190408
  },
@@ -190792,8 +191419,8 @@ function isNoiseObservation(obs) {
190792
191419
  return NOISE_PATTERNS.some((pattern) => pattern.test(title)) || isCommandTrace(obs);
190793
191420
  }
190794
191421
  function isSystemSelfObservation(obs) {
190795
- const text = stringifyObservation(obs, false);
190796
- return SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(text));
191422
+ const text2 = stringifyObservation(obs, false);
191423
+ return SYSTEM_SELF_PATTERNS.some((pattern) => pattern.test(text2));
190797
191424
  }
190798
191425
  function readerForAlias(reader, aliases, observation) {
190799
191426
  if (!reader) return void 0;
@@ -190816,8 +191443,8 @@ function continuationTaskTokens(task) {
190816
191443
  function continuationScore(observation, projectTokens, task) {
190817
191444
  let score = scoreObservationForSessionContext(observation, projectTokens);
190818
191445
  if (observation.type === "session-request" || observation.type === "what-changed") score += 1;
190819
- const text = stringifyObservation(observation);
190820
- const matches = continuationTaskTokens(task).filter((token) => text.includes(token)).length;
191446
+ const text2 = stringifyObservation(observation);
191447
+ const matches = continuationTaskTokens(task).filter((token) => text2.includes(token)).length;
190821
191448
  score += Math.min(matches, 2) * 2;
190822
191449
  return score;
190823
191450
  }
@@ -190851,8 +191478,8 @@ async function getSessionResumeBrief(projectId, task, reader) {
190851
191478
  memories
190852
191479
  };
190853
191480
  }
190854
- function compactResumeText(text, limit2) {
190855
- const normalized = text.replace(/\s+/g, " ").trim();
191481
+ function compactResumeText(text2, limit2) {
191482
+ const normalized = text2.replace(/\s+/g, " ").trim();
190856
191483
  return normalized.length <= limit2 ? normalized : `${normalized.slice(0, Math.max(0, limit2 - 3)).trimEnd()}...`;
190857
191484
  }
190858
191485
  function renderSessionResumeCard(brief) {
@@ -190874,11 +191501,11 @@ function renderSessionResumeCard(brief) {
190874
191501
  }
190875
191502
  function scoreObservationForSessionContext(obs, projectTokens, now3 = Date.now()) {
190876
191503
  let score = TYPE_WEIGHTS[obs.type] ?? 1;
190877
- const text = stringifyObservation(obs);
191504
+ const text2 = stringifyObservation(obs);
190878
191505
  const ageDays = Math.max(0, (now3 - new Date(obs.createdAt).getTime()) / (1e3 * 60 * 60 * 24));
190879
191506
  score += Math.max(0.2, 2.5 - Math.min(ageDays, 45) * 0.05);
190880
191507
  if (projectTokens.length > 0) {
190881
- const matchingTokens = projectTokens.filter((token) => text.includes(token));
191508
+ const matchingTokens = projectTokens.filter((token) => text2.includes(token));
190882
191509
  if (matchingTokens.length > 0) {
190883
191510
  score += 2 + matchingTokens.length * 0.6;
190884
191511
  } else if ((obs.filesModified?.length ?? 0) > 0) {
@@ -191194,8 +191821,8 @@ var compaction_checkpoint_store_exports = {};
191194
191821
  __export(compaction_checkpoint_store_exports, {
191195
191822
  CompactionCheckpointStore: () => CompactionCheckpointStore
191196
191823
  });
191197
- import { createHash as createHash13, randomUUID as randomUUID14 } from "crypto";
191198
- function optionalText6(value) {
191824
+ import { createHash as createHash13, randomUUID as randomUUID15 } from "crypto";
191825
+ function optionalText7(value) {
191199
191826
  return typeof value === "string" && value ? value : void 0;
191200
191827
  }
191201
191828
  function optionalNumber2(value) {
@@ -191249,15 +191876,15 @@ function rowToCheckpoint(row) {
191249
191876
  reason: row.reason,
191250
191877
  sourceEvent: row.source_event,
191251
191878
  sourceKey: row.source_key,
191252
- ...optionalText6(row.summary) ? { summary: row.summary } : {},
191879
+ ...optionalText7(row.summary) ? { summary: row.summary } : {},
191253
191880
  ...optionalNumber2(row.tokens_before) !== void 0 ? { tokensBefore: Number(row.tokens_before) } : {},
191254
- ...optionalText6(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
191881
+ ...optionalText7(row.first_kept_entry_id) ? { firstKeptEntryId: row.first_kept_entry_id } : {},
191255
191882
  ...parseDetails(row.details_json) ? { details: parseDetails(row.details_json) } : {},
191256
191883
  transcriptAvailable: Boolean(row.transcript_available),
191257
191884
  status: row.status,
191258
191885
  preCapturedAt: row.pre_captured_at,
191259
- ...optionalText6(row.completed_at) ? { completedAt: row.completed_at } : {},
191260
- ...optionalText6(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
191886
+ ...optionalText7(row.completed_at) ? { completedAt: row.completed_at } : {},
191887
+ ...optionalText7(row.delivered_at) ? { deliveredAt: row.delivered_at } : {},
191261
191888
  deliveryCount: Number(row.delivery_count ?? 0),
191262
191889
  createdAt: row.created_at,
191263
191890
  updatedAt: row.updated_at
@@ -191295,7 +191922,7 @@ var init_compaction_checkpoint_store = __esm({
191295
191922
  if (pending) return rowToCheckpoint(pending);
191296
191923
  const now3 = input.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString();
191297
191924
  const checkpoint = {
191298
- id: randomUUID14(),
191925
+ id: randomUUID15(),
191299
191926
  projectId: input.projectId,
191300
191927
  sessionId: input.sessionId,
191301
191928
  agent: input.agent,
@@ -191303,7 +191930,7 @@ var init_compaction_checkpoint_store = __esm({
191303
191930
  captureKind: "preflight",
191304
191931
  reason: safeReason(input.reason),
191305
191932
  sourceEvent: input.sourceEvent,
191306
- sourceKey: `pre:${randomUUID14()}`,
191933
+ sourceKey: `pre:${randomUUID15()}`,
191307
191934
  transcriptAvailable: Boolean(input.transcriptAvailable),
191308
191935
  status: "active",
191309
191936
  preCapturedAt: now3,
@@ -191369,7 +191996,7 @@ var init_compaction_checkpoint_store = __esm({
191369
191996
  return this.get(checkpoint2.id);
191370
191997
  }
191371
191998
  const checkpoint = {
191372
- id: randomUUID14(),
191999
+ id: randomUUID15(),
191373
192000
  projectId: input.projectId,
191374
192001
  sessionId: input.sessionId,
191375
192002
  agent: input.agent,
@@ -191631,6 +192258,25 @@ async function buildAutoProjectContext(input) {
191631
192258
  const overview = explain.overview;
191632
192259
  const currentFacts = collectCurrentProjectFacts({ project: input.project, now: now3 });
191633
192260
  const latestSnapshot = overview.code.latestSnapshot;
192261
+ let codeEvolution;
192262
+ if (continuationRequested && latestSnapshot?.previousSnapshotId && latestSnapshot.changedPathCount > 0) {
192263
+ const diff = store2.diffSnapshots(input.project.id, latestSnapshot.previousSnapshotId, latestSnapshot.id);
192264
+ if (diff.available && diff.changes.length > 0) {
192265
+ const impact = store2.impactSlice(input.project.id, diff.changes.map((change) => change.path));
192266
+ const changedFileIds = new Set([
192267
+ ...store2.listSnapshotFiles(diff.fromSnapshotId),
192268
+ ...store2.listSnapshotFiles(diff.toSnapshotId)
192269
+ ].filter((file2) => diff.changes.some((change) => change.path === file2.path)).map((file2) => file2.fileId));
192270
+ codeEvolution = {
192271
+ fromSnapshotId: diff.fromSnapshotId,
192272
+ toSnapshotId: diff.toSnapshotId,
192273
+ changes: diff.changes.slice(0, 5).map((change) => ({ path: change.path, kind: change.kind })),
192274
+ directlyConnectedPaths: impact.directlyConnectedPaths.slice(0, 3),
192275
+ affectedMemoryCount: store2.countStaleObservationRefsForFiles(input.project.id, [...changedFileIds]),
192276
+ truncated: impact.truncated || diff.changes.length > 5
192277
+ };
192278
+ }
192279
+ }
191634
192280
  const sourceSets = lensSourceSets({ task, lens, explain });
191635
192281
  let externalOutline;
191636
192282
  let externalCaution;
@@ -191707,6 +192353,7 @@ async function buildAutoProjectContext(input) {
191707
192353
  currentFacts: worksetFactLines(currentFacts),
191708
192354
  ...continuation ? { continuation } : {},
191709
192355
  codeState: codeStateLine(overview),
192356
+ ...codeEvolution ? { codeEvolution } : {},
191710
192357
  reliableMemory: sourceSets.reliableSources.slice(0, lens.sourceLimit).map((source) => ({
191711
192358
  id: source.observationId,
191712
192359
  title: source.title,
@@ -191758,9 +192405,9 @@ async function buildAutoProjectContext(input) {
191758
192405
  function formatLanguages(overview) {
191759
192406
  return overview.code.languages.length > 0 ? overview.code.languages.map((item) => `${item.language} ${item.files}`).join(", ") : "none indexed yet";
191760
192407
  }
191761
- function compactContinuationText(text, budget) {
192408
+ function compactContinuationText(text2, budget) {
191762
192409
  return truncateToTokenBudget(
191763
- sanitizeCredentials(text).replace(/\s+/g, " ").trim(),
192410
+ sanitizeCredentials(text2).replace(/\s+/g, " ").trim(),
191764
192411
  budget
191765
192412
  );
191766
192413
  }
@@ -192173,6 +192820,13 @@ function formatContextReceipt(receipt) {
192173
192820
  lines.push(`- ${item.kind}: ${item.count} item(s) (${item.reason})`);
192174
192821
  }
192175
192822
  }
192823
+ if (receipt.governance?.decisions.length) {
192824
+ lines.push("", "Optional evidence qualification");
192825
+ for (const item of receipt.governance.decisions.slice(0, 20)) {
192826
+ const id = item.id ? ` ${item.id}` : "";
192827
+ lines.push(`- ${item.kind}${id}: ${item.disposition} (${item.reasons.join(", ")})`);
192828
+ }
192829
+ }
192176
192830
  if (receipt.scheduledActions.length > 0) {
192177
192831
  lines.push("", "Scheduled follow-up");
192178
192832
  for (const action of receipt.scheduledActions) lines.push(`- ${action}`);
@@ -192252,8 +192906,8 @@ __export(context_pack_exports, {
192252
192906
  function uniq2(items) {
192253
192907
  return [...new Set(items)];
192254
192908
  }
192255
- function tokenize5(text) {
192256
- return (text.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1);
192909
+ function tokenize5(text2) {
192910
+ return (text2.toLowerCase().match(/[a-z0-9_./-]+|[\u4e00-\u9fff]+/g) ?? []).map((token) => token.trim()).filter((token) => token.length > 1);
192257
192911
  }
192258
192912
  function timestampOf(observation) {
192259
192913
  return Date.parse(observation.updatedAt ?? observation.createdAt ?? "") || 0;
@@ -192515,11 +193169,49 @@ function formatUsageHint() {
192515
193169
  "Usage:",
192516
193170
  " memorix codegraph refresh",
192517
193171
  " memorix codegraph status --json",
193172
+ " memorix codegraph diff [--from <snapshot>] [--to <snapshot>]",
193173
+ " memorix codegraph impact --path <relative-source-path>",
192518
193174
  ' memorix codegraph context-pack --task "continue auth bug"',
192519
193175
  "",
192520
193176
  'Tip: use `memorix context "..."` for new work or `memorix resume "..."` for prior work.'
192521
193177
  ].join("\n");
192522
193178
  }
193179
+ function formatDiff(diff, impact) {
193180
+ if (!diff.available) {
193181
+ return `CodeGraph diff is unavailable: ${diff.reason ?? "unknown reason"}. Refresh twice to establish comparable snapshots.`;
193182
+ }
193183
+ const summary = diff.changes.reduce((counts, change) => {
193184
+ counts[change.kind] += 1;
193185
+ return counts;
193186
+ }, { added: 0, modified: 0, removed: 0 });
193187
+ const lines = [
193188
+ `CodeGraph diff: ${diff.fromSnapshotId} -> ${diff.toSnapshotId}`,
193189
+ `- Changed files: ${diff.changes.length} (${summary.added} added, ${summary.modified} modified, ${summary.removed} removed)`
193190
+ ];
193191
+ for (const change of diff.changes.slice(0, 20)) lines.push(`- ${change.kind}: ${change.path}`);
193192
+ if (diff.changes.length > 20) lines.push(`- ${diff.changes.length - 20} additional file change(s) omitted`);
193193
+ if (impact.directlyConnectedPaths.length > 0) {
193194
+ lines.push("", "Current one-hop structural impact");
193195
+ for (const path46 of impact.directlyConnectedPaths.slice(0, 20)) lines.push(`- ${path46}`);
193196
+ }
193197
+ if (impact.relationCount === 0) lines.push("", "No current file-edge relation was found for the changed paths.");
193198
+ if (impact.truncated) lines.push("- Impact relation limit reached; inspect the graph before assuming coverage.");
193199
+ return lines.join("\n");
193200
+ }
193201
+ function formatImpact(impact) {
193202
+ const lines = [
193203
+ `CodeGraph current one-hop impact: ${impact.changedPaths.join(", ")}`,
193204
+ `- Relations inspected: ${impact.relationCount}`
193205
+ ];
193206
+ if (impact.directlyConnectedPaths.length > 0) {
193207
+ lines.push("- Directly connected paths:");
193208
+ for (const path46 of impact.directlyConnectedPaths) lines.push(` - ${path46}`);
193209
+ } else {
193210
+ lines.push("- No current file-edge relation was found for this indexed path.");
193211
+ }
193212
+ if (impact.truncated) lines.push("- Impact relation limit reached; inspect the graph before assuming coverage.");
193213
+ return lines.join("\n");
193214
+ }
192523
193215
  function compactFacts(project) {
192524
193216
  const current = collectCurrentProjectFacts({ project, now: /* @__PURE__ */ new Date() });
192525
193217
  const facts = [];
@@ -192553,9 +193245,13 @@ var init_codegraph = __esm({
192553
193245
  description: "Inspect and refresh CodeGraph Memory for the current project"
192554
193246
  },
192555
193247
  args: {
192556
- action: { type: "string", description: "Action: status, refresh, or context-pack" },
193248
+ action: { type: "string", description: "Action: status, refresh, diff, impact, or context-pack" },
192557
193249
  task: { type: "string", description: "Task text for context-pack" },
193250
+ path: { type: "string", description: "Indexed relative source path for impact" },
192558
193251
  limit: { type: "string", description: "Max active memories to inspect for context-pack" },
193252
+ from: { type: "string", description: "Earlier CodeGraph snapshot id for diff" },
193253
+ to: { type: "string", description: "Later CodeGraph snapshot id for diff" },
193254
+ impactLimit: { type: "string", description: "Maximum graph relations to inspect for diff impact" },
192559
193255
  json: { type: "boolean", description: "Emit machine-readable JSON output" }
192560
193256
  },
192561
193257
  run: async ({ args }) => {
@@ -192578,10 +193274,10 @@ var init_codegraph = __esm({
192578
193274
  command: codegraphConfig.externalCommand,
192579
193275
  timeoutMs: codegraphConfig.externalTimeoutMs
192580
193276
  });
192581
- const text = explicitAction || asJson ? formatStatus(status, providerQuality2.quality) : `${formatStatus(status, providerQuality2.quality)}
193277
+ const text2 = explicitAction || asJson ? formatStatus(status, providerQuality2.quality) : `${formatStatus(status, providerQuality2.quality)}
192582
193278
 
192583
193279
  ${formatUsageHint()}`;
192584
- emitResult({ project, status, providerQuality: providerQuality2.quality }, text, asJson);
193280
+ emitResult({ project, status, providerQuality: providerQuality2.quality }, text2, asJson);
192585
193281
  return;
192586
193282
  }
192587
193283
  case "refresh": {
@@ -192628,6 +193324,41 @@ ${formatUsageHint()}`;
192628
193324
  );
192629
193325
  return;
192630
193326
  }
193327
+ case "diff": {
193328
+ const snapshots = store2.listSnapshots(project.id, 2);
193329
+ const fromSnapshotId = args.from?.trim() || snapshots[1]?.id;
193330
+ const toSnapshotId = args.to?.trim() || snapshots[0]?.id;
193331
+ if (!fromSnapshotId || !toSnapshotId) {
193332
+ emitError('two completed CodeGraph snapshots are required; run "memorix codegraph refresh" again after a code change.', asJson);
193333
+ return;
193334
+ }
193335
+ const diff = store2.diffSnapshots(project.id, fromSnapshotId, toSnapshotId);
193336
+ const impact = store2.impactSlice(
193337
+ project.id,
193338
+ diff.changes.map((change) => change.path),
193339
+ parsePositiveInt(args.impactLimit, 24)
193340
+ );
193341
+ emitResult({ project, diff, impact }, formatDiff(diff, impact), asJson);
193342
+ return;
193343
+ }
193344
+ case "impact": {
193345
+ const sourcePath = args.path?.trim() || positional.slice(1).join(" ").trim();
193346
+ if (!sourcePath) {
193347
+ emitError('path is required for "memorix codegraph impact"', asJson);
193348
+ return;
193349
+ }
193350
+ if (!store2.getFile(project.id, sourcePath)) {
193351
+ emitError(`path is not in the current CodeGraph index: ${sourcePath}. Run "memorix codegraph refresh" and retry.`, asJson);
193352
+ return;
193353
+ }
193354
+ const impact = store2.impactSlice(
193355
+ project.id,
193356
+ [sourcePath],
193357
+ parsePositiveInt(args.impactLimit, 24)
193358
+ );
193359
+ emitResult({ project, impact }, formatImpact(impact), asJson);
193360
+ return;
193361
+ }
192631
193362
  case "context-pack": {
192632
193363
  const task = args.task?.trim() || positional.slice(1).join(" ").trim();
192633
193364
  if (!task) {
@@ -192683,7 +193414,7 @@ ${formatUsageHint()}`;
192683
193414
  return;
192684
193415
  }
192685
193416
  default:
192686
- emitError(`unknown codegraph action "${action}". Use "status", "refresh", or "context-pack".`, asJson);
193417
+ emitError(`unknown codegraph action "${action}". Use "status", "refresh", "diff", "impact", or "context-pack".`, asJson);
192687
193418
  }
192688
193419
  } catch (error40) {
192689
193420
  emitError(error40 instanceof Error ? error40.message : String(error40), asJson);
@@ -192726,19 +193457,19 @@ function buildCompactionWorkset(checkpoint, options2 = {}) {
192726
193457
  const source = sanitizeCredentials(checkpoint.summary?.trim() || fallback);
192727
193458
  const available = Math.max(0, budget - countTextTokens(header) - 4);
192728
193459
  let excerpt = source ? truncateToTokenBudget(source, available) : "";
192729
- let text = `${header}${excerpt ? `### Host checkpoint
193460
+ let text2 = `${header}${excerpt ? `### Host checkpoint
192730
193461
  ${excerpt}` : ""}`.trim();
192731
- while (excerpt && countTextTokens(text) > budget) {
193462
+ while (excerpt && countTextTokens(text2) > budget) {
192732
193463
  const nextExcerptBudget = Math.max(1, Math.floor(countTextTokens(excerpt) * 0.8));
192733
193464
  excerpt = truncateToTokenBudget(excerpt, nextExcerptBudget);
192734
- text = `${header}${excerpt ? `### Host checkpoint
193465
+ text2 = `${header}${excerpt ? `### Host checkpoint
192735
193466
  ${excerpt}` : ""}`.trim();
192736
193467
  }
192737
- if (countTextTokens(text) > budget) text = truncateToTokenBudget(text, budget);
193468
+ if (countTextTokens(text2) > budget) text2 = truncateToTokenBudget(text2, budget);
192738
193469
  return {
192739
193470
  checkpointId: checkpoint.id,
192740
- text,
192741
- tokens: countTextTokens(text)
193471
+ text: text2,
193472
+ tokens: countTextTokens(text2)
192742
193473
  };
192743
193474
  }
192744
193475
  function sourceEvent(input) {
@@ -192989,9 +193720,9 @@ function usage2() {
192989
193720
  ].join("\n");
192990
193721
  }
192991
193722
  function requiredText2(value, field) {
192992
- const text = typeof value === "string" ? value.trim() : "";
192993
- if (!text) throw new Error(field + " is required");
192994
- return text;
193723
+ const text2 = typeof value === "string" ? value.trim() : "";
193724
+ if (!text2) throw new Error(field + " is required");
193725
+ return text2;
192995
193726
  }
192996
193727
  function workflowOutcome(value) {
192997
193728
  if (value === "passed" || value === "failed" || value === "cancelled" || value === "in-progress") return value;
@@ -193584,8 +194315,8 @@ async function extractFactsWithLLM(narrative, title, existingFacts) {
193584
194315
  Content: ${narrative}${existingFacts.length > 0 ? `
193585
194316
  Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
193586
194317
  const response = await callLLM2(LLM_EXTRACT_PROMPT, input);
193587
- const text = response.content.trim();
193588
- const jsonMatch = text.match(/\{[\s\S]*\}/);
194318
+ const text2 = response.content.trim();
194319
+ const jsonMatch = text2.match(/\{[\s\S]*\}/);
193589
194320
  if (!jsonMatch) return [];
193590
194321
  const parsed = JSON.parse(jsonMatch[0]);
193591
194322
  const facts = parsed.facts;
@@ -193838,8 +194569,8 @@ Facts: ${extracted.facts.join("; ")}
193838
194569
  EXISTING MEMORIES:
193839
194570
  ${existingMemories.map((m5) => `[ID:${m5.id}] ${m5.title} | ${m5.content} | Facts: ${m5.facts}`).join("\n")}`;
193840
194571
  const response = await callLLM2(LLM_RESOLVE_PROMPT, input);
193841
- const text = response.content.trim();
193842
- const jsonMatch = text.match(/\{[\s\S]*\}/);
194572
+ const text2 = response.content.trim();
194573
+ const jsonMatch = text2.match(/\{[\s\S]*\}/);
193843
194574
  if (!jsonMatch) return null;
193844
194575
  const parsed = JSON.parse(jsonMatch[0]);
193845
194576
  const action = parsed.action?.toUpperCase();
@@ -195486,9 +196217,9 @@ __export(identity_exports, {
195486
196217
  default: () => identity_default
195487
196218
  });
195488
196219
  function requiredText3(value, label) {
195489
- const text = typeof value === "string" ? value.trim() : "";
195490
- if (!text) throw new Error(`${label} is required`);
195491
- return text;
196220
+ const text2 = typeof value === "string" ? value.trim() : "";
196221
+ if (!text2) throw new Error(`${label} is required`);
196222
+ return text2;
195492
196223
  }
195493
196224
  var identity_default;
195494
196225
  var init_identity2 = __esm({
@@ -196164,15 +196895,15 @@ function validateSemantics(graph) {
196164
196895
  return warnings;
196165
196896
  }
196166
196897
  function extractJson(raw) {
196167
- let text = raw;
196898
+ let text2 = raw;
196168
196899
  try {
196169
196900
  const envelope = JSON.parse(raw.trim());
196170
196901
  if (envelope && typeof envelope.result === "string" && envelope.type === "result") {
196171
- text = envelope.result;
196902
+ text2 = envelope.result;
196172
196903
  }
196173
196904
  } catch {
196174
196905
  }
196175
- if (text === raw && raw.includes('"type"')) {
196906
+ if (text2 === raw && raw.includes('"type"')) {
196176
196907
  const textBlocks = [];
196177
196908
  for (const line of raw.split("\n")) {
196178
196909
  const trimmed = line.trim();
@@ -196196,27 +196927,27 @@ function extractJson(raw) {
196196
196927
  }
196197
196928
  }
196198
196929
  if (textBlocks.length > 0) {
196199
- text = textBlocks.join("");
196930
+ text2 = textBlocks.join("");
196200
196931
  }
196201
196932
  }
196202
- const fenced = text.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
196933
+ const fenced = text2.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
196203
196934
  if (fenced) {
196204
196935
  const candidate2 = fenced[1].trim();
196205
196936
  if (candidate2.startsWith("{")) return candidate2;
196206
196937
  }
196207
- const braceStart = text.indexOf("{");
196938
+ const braceStart = text2.indexOf("{");
196208
196939
  if (braceStart !== -1) {
196209
- const extracted = extractBalancedJson(text, braceStart);
196940
+ const extracted = extractBalancedJson(text2, braceStart);
196210
196941
  if (extracted) return extracted;
196211
196942
  }
196212
196943
  return null;
196213
196944
  }
196214
- function extractBalancedJson(text, startIdx) {
196945
+ function extractBalancedJson(text2, startIdx) {
196215
196946
  let depth = 0;
196216
196947
  let inString = false;
196217
196948
  let escape2 = false;
196218
- for (let i3 = startIdx; i3 < text.length; i3++) {
196219
- const ch = text[i3];
196949
+ for (let i3 = startIdx; i3 < text2.length; i3++) {
196950
+ const ch = text2[i3];
196220
196951
  if (escape2) {
196221
196952
  escape2 = false;
196222
196953
  continue;
@@ -196234,7 +196965,7 @@ function extractBalancedJson(text, startIdx) {
196234
196965
  else if (ch === "}") {
196235
196966
  depth--;
196236
196967
  if (depth === 0) {
196237
- return text.slice(startIdx, i3 + 1);
196968
+ return text2.slice(startIdx, i3 + 1);
196238
196969
  }
196239
196970
  }
196240
196971
  }
@@ -196454,7 +197185,7 @@ __export(planner_exports, {
196454
197185
  materializeTaskGraph: () => materializeTaskGraph,
196455
197186
  seedAutonomousPipeline: () => seedAutonomousPipeline
196456
197187
  });
196457
- import { randomUUID as randomUUID15 } from "crypto";
197188
+ import { randomUUID as randomUUID16 } from "crypto";
196458
197189
  function isPlannerTask(metadata) {
196459
197190
  if (!metadata) return null;
196460
197191
  try {
@@ -196512,7 +197243,7 @@ function seedAutonomousPipeline(teamStore, projectId, config2, opts) {
196512
197243
  const maxIterations = config2.maxIterations ?? 3;
196513
197244
  const taskBudget = config2.taskBudget ?? 15;
196514
197245
  const structuredPlan = opts?.structuredPlan ?? true;
196515
- const pipelineId = randomUUID15();
197246
+ const pipelineId = randomUUID16();
196516
197247
  const meta = {
196517
197248
  plannerType: "plan",
196518
197249
  pipelineId,
@@ -197408,7 +198139,7 @@ var init_poll2 = __esm({
197408
198139
  if (args.markInboxRead && agentId) {
197409
198140
  teamStore.markAllRead(project.id, agentId);
197410
198141
  }
197411
- const text = [
198142
+ const text2 = [
197412
198143
  poll.agent ? `You: ${shortId(poll.agent.agentId)} (${poll.agent.status})` : "Project-level overview",
197413
198144
  poll.watermark.newObservationCount > 0 ? `${poll.watermark.newObservationCount} new observation(s)` : "No unseen observations",
197414
198145
  poll.inbox.unreadCount > 0 ? `${poll.inbox.unreadCount} unread message(s)` : "Inbox clear",
@@ -197416,7 +198147,7 @@ var init_poll2 = __esm({
197416
198147
  poll.tasks.availableToClaim.length > 0 ? `${poll.tasks.availableToClaim.length} task(s) available to claim` : "No claimable tasks",
197417
198148
  `Team: ${poll.team.activeAgents.length} active / ${poll.team.totalAgents} total`
197418
198149
  ].join("\n");
197419
- emitResult({ project, poll }, text, asJson);
198150
+ emitResult({ project, poll }, text2, asJson);
197420
198151
  } catch (error40) {
197421
198152
  emitError(error40 instanceof Error ? error40.message : String(error40), asJson);
197422
198153
  }
@@ -197492,8 +198223,8 @@ async function loadReceiptObservations(dataDir, projectId) {
197492
198223
  function probeMatches(obs, probe) {
197493
198224
  const query = probe.toLowerCase();
197494
198225
  const facts = safeJsonArray(obs.facts).join(" ");
197495
- const text = [obs.title ?? "", obs.narrative ?? "", facts].join(" ").toLowerCase();
197496
- return query.split(/\s+/).filter(Boolean).some((term) => text.includes(term));
198226
+ const text2 = [obs.title ?? "", obs.narrative ?? "", facts].join(" ").toLowerCase();
198227
+ return query.split(/\s+/).filter(Boolean).some((term) => text2.includes(term));
197497
198228
  }
197498
198229
  async function buildHandoffReceipt(options2 = {}) {
197499
198230
  const cwd = options2.cwd ?? process.cwd();
@@ -205234,7 +205965,7 @@ var require_core2 = __commonJS({
205234
205965
  errorsText(errors2 = this.errors, { separator: separator10 = ", ", dataVar = "data" } = {}) {
205235
205966
  if (!errors2 || errors2.length === 0)
205236
205967
  return "No errors";
205237
- return errors2.map((e4) => `${dataVar}${e4.instancePath} ${e4.message}`).reduce((text, msg) => text + separator10 + msg);
205968
+ return errors2.map((e4) => `${dataVar}${e4.instancePath} ${e4.message}`).reduce((text2, msg) => text2 + separator10 + msg);
205238
205969
  }
205239
205970
  $dataMetaSchema(metaSchema, keywordsJsonPointers) {
205240
205971
  const rules = this.RULES.all;
@@ -207219,7 +207950,7 @@ var require_discriminator = __commonJS({
207219
207950
  error: error40,
207220
207951
  code(cxt) {
207221
207952
  const { gen, data, schema, parentSchema, it } = cxt;
207222
- const { oneOf } = parentSchema;
207953
+ const { oneOf: oneOf2 } = parentSchema;
207223
207954
  if (!it.opts.discriminator) {
207224
207955
  throw new Error("discriminator: requires discriminator option");
207225
207956
  }
@@ -207228,7 +207959,7 @@ var require_discriminator = __commonJS({
207228
207959
  throw new Error("discriminator: requires propertyName");
207229
207960
  if (schema.mapping)
207230
207961
  throw new Error("discriminator: mapping is not supported");
207231
- if (!oneOf)
207962
+ if (!oneOf2)
207232
207963
  throw new Error("discriminator: requires oneOf keyword");
207233
207964
  const valid = gen.let("valid", false);
207234
207965
  const tag = gen.const("tag", (0, codegen_1._)`${data}${(0, codegen_1.getProperty)(tagName)}`);
@@ -207256,8 +207987,8 @@ var require_discriminator = __commonJS({
207256
207987
  const oneOfMapping = {};
207257
207988
  const topRequired = hasRequired(parentSchema);
207258
207989
  let tagRequired = true;
207259
- for (let i3 = 0; i3 < oneOf.length; i3++) {
207260
- let sch = oneOf[i3];
207990
+ for (let i3 = 0; i3 < oneOf2.length; i3++) {
207991
+ let sch = oneOf2[i3];
207261
207992
  if ((sch === null || sch === void 0 ? void 0 : sch.$ref) && !(0, util_1.schemaHasRulesButRef)(sch, it.self.RULES)) {
207262
207993
  const ref = sch.$ref;
207263
207994
  sch = compile_1.resolveRef.call(it.self, it.schemaEnv.root, it.baseId, ref);
@@ -212816,8 +213547,8 @@ async function callVisionLLM(systemPrompt, imageBase64, mimeType) {
212816
213547
  return data.choices[0]?.message?.content ?? "";
212817
213548
  }
212818
213549
  function normalizeText4(value, fallback = "") {
212819
- const text = typeof value === "string" && value.trim() ? value.trim() : fallback;
212820
- return sanitizeCredentials(text).slice(0, MAX_VISION_DESCRIPTION_CHARS);
213550
+ const text2 = typeof value === "string" && value.trim() ? value.trim() : fallback;
213551
+ return sanitizeCredentials(text2).slice(0, MAX_VISION_DESCRIPTION_CHARS);
212821
213552
  }
212822
213553
  function normalizeLabels(value) {
212823
213554
  if (!Array.isArray(value)) return [];
@@ -213306,7 +214037,7 @@ The path should point to a directory containing a .git folder.`
213306
214037
  };
213307
214038
  const server = existingServer ?? new McpServer({
213308
214039
  name: "memorix",
213309
- version: true ? "1.4.0" : "1.0.1"
214040
+ version: true ? "1.4.2" : "1.0.1"
213310
214041
  });
213311
214042
  const originalRegisterTool = server.registerTool.bind(server);
213312
214043
  server.registerTool = ((name, ...args) => {
@@ -214042,10 +214773,10 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
214042
214773
  const duplicate = blockCoveredAutopilotEvidence("memorix_search", result.entries.map((entry) => entry.id), force);
214043
214774
  if (duplicate) return duplicate;
214044
214775
  }
214045
- let text = result.formatted;
214776
+ let text2 = result.formatted;
214046
214777
  try {
214047
214778
  const { getLastSearchMode: getLastSearchMode2 } = await Promise.resolve().then(() => (init_orama_store(), orama_store_exports));
214048
- text += `
214779
+ text2 += `
214049
214780
 
214050
214781
  _Search mode: ${getLastSearchMode2(project.id)}_`;
214051
214782
  } catch {
@@ -214054,7 +214785,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214054
214785
  content: [
214055
214786
  {
214056
214787
  type: "text",
214057
- text
214788
+ text: text2
214058
214789
  }
214059
214790
  ]
214060
214791
  };
@@ -214087,14 +214818,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214087
214818
  query,
214088
214819
  limit: limit2 != null ? coerceNumber(limit2, 5) : void 0
214089
214820
  });
214090
- const text = format === "summary" ? [
214821
+ const text2 = format === "summary" ? [
214091
214822
  `Graph context packet for ${project.name}`,
214092
214823
  `- ${packet.summary}`,
214093
214824
  "",
214094
214825
  ...packet.entities.map((entity) => `* ${entity.name} (#${entity.observationIds.join(", #")})`)
214095
214826
  ].join("\n") : formatGraphContextPrompt(packet);
214096
214827
  return {
214097
- content: [{ type: "text", text }]
214828
+ content: [{ type: "text", text: text2 }]
214098
214829
  };
214099
214830
  }
214100
214831
  );
@@ -214154,7 +214885,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214154
214885
  });
214155
214886
  }
214156
214887
  });
214157
- const text = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
214888
+ const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
214158
214889
  autopilotRetrievalBoundary = {
214159
214890
  projectId: project.id,
214160
214891
  issuedAt: Date.now(),
@@ -214166,7 +214897,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214166
214897
  readOnly: READ_ONLY_TASK_PATTERN.test(task ?? "")
214167
214898
  };
214168
214899
  return {
214169
- content: [{ type: "text", text }]
214900
+ content: [{ type: "text", text: text2 }]
214170
214901
  };
214171
214902
  }
214172
214903
  );
@@ -214294,9 +215025,9 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214294
215025
  ...external.caution ? { runtimeCautions: [{ kind: "external-codegraph-fallback", message: external.caution }] } : {},
214295
215026
  reader: getObservationReader()
214296
215027
  });
214297
- const text = buildContextPackPrompt2(pack);
215028
+ const text2 = buildContextPackPrompt2(pack);
214298
215029
  return {
214299
- content: [{ type: "text", text }]
215030
+ content: [{ type: "text", text: text2 }]
214300
215031
  };
214301
215032
  }
214302
215033
  );
@@ -214358,7 +215089,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214358
215089
  }) => {
214359
215090
  const unresolved = requireResolvedProject("manage the Knowledge Workspace for the current project");
214360
215091
  if (unresolved) return unresolved;
214361
- const text = (value, isError = false) => ({
215092
+ const text2 = (value, isError = false) => ({
214362
215093
  content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
214363
215094
  ...isError ? { isError: true } : {}
214364
215095
  });
@@ -214395,7 +215126,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214395
215126
  ]);
214396
215127
  if (action === "workspace_init") {
214397
215128
  if (modeValue === "versioned" && !requireText(workspacePath, "path")) {
214398
- return text({ error: "path is required to initialize a versioned Knowledge Workspace." }, true);
215129
+ return text2({ error: "path is required to initialize a versioned Knowledge Workspace." }, true);
214399
215130
  }
214400
215131
  const workspace2 = await initializeKnowledgeWorkspace2({
214401
215132
  projectId: project.id,
@@ -214403,7 +215134,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214403
215134
  mode: modeValue,
214404
215135
  ...modeValue === "versioned" ? { projectRoot: project.rootPath, rootPath: requireText(workspacePath, "path") } : {}
214405
215136
  });
214406
- return text({
215137
+ return text2({
214407
215138
  workspace: {
214408
215139
  id: workspace2.id,
214409
215140
  mode: workspace2.mode,
@@ -214415,7 +215146,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214415
215146
  }
214416
215147
  const workspace = await loadKnowledgeWorkspace2({ projectId: project.id, dataDir: projectDir2, mode: modeValue });
214417
215148
  if (!workspace) {
214418
- return text({ error: "Knowledge Workspace is not initialized. Run workspace_init first." }, true);
215149
+ return text2({ error: "Knowledge Workspace is not initialized. Run workspace_init first." }, true);
214419
215150
  }
214420
215151
  const claims = new ClaimStore2();
214421
215152
  const workspaceStore = new KnowledgeWorkspaceStore2();
@@ -214423,7 +215154,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214423
215154
  if (action === "status") {
214424
215155
  const pages = workspaceStore.listPages(workspace.id);
214425
215156
  const pending = workspaceStore.listProposals(workspace.id, "pending");
214426
- return text({
215157
+ return text2({
214427
215158
  workspace: {
214428
215159
  id: workspace.id,
214429
215160
  mode: workspace.mode,
@@ -214441,7 +215172,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214441
215172
  });
214442
215173
  }
214443
215174
  if (action === "claim_list") {
214444
- return text({
215175
+ return text2({
214445
215176
  claims: claims.listClaims(project.id, { limit: 100 }).map((claim) => ({
214446
215177
  id: claim.id,
214447
215178
  subject: claim.subject,
@@ -214460,18 +215191,18 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214460
215191
  const requestedClaimId = requireText(claimId, "claimId");
214461
215192
  const detail = requireText(reviewDetail, "reviewDetail");
214462
215193
  if (!requestedClaimId || !claimReviewState2 || !detail) {
214463
- return text({ error: "claimId, claimReviewState, and reviewDetail are required for claim_review." }, true);
215194
+ return text2({ error: "claimId, claimReviewState, and reviewDetail are required for claim_review." }, true);
214464
215195
  }
214465
215196
  const existing = claims.getClaim(requestedClaimId);
214466
215197
  if (!existing || existing.projectId !== project.id) {
214467
- return text({ error: "Claim was not found for the current project." }, true);
215198
+ return text2({ error: "Claim was not found for the current project." }, true);
214468
215199
  }
214469
215200
  const claim = reviewClaim2(claims, {
214470
215201
  claimId: requestedClaimId,
214471
215202
  reviewState: claimReviewState2,
214472
215203
  detail
214473
215204
  });
214474
- return text({
215205
+ return text2({
214475
215206
  claim: {
214476
215207
  id: claim.id,
214477
215208
  status: claim.status,
@@ -214483,7 +215214,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214483
215214
  }
214484
215215
  if (action === "compile") {
214485
215216
  const result = await compileKnowledgeWorkspace2({ workspace, claims });
214486
- return text({
215217
+ return text2({
214487
215218
  proposals: result.proposals.map((proposal) => ({
214488
215219
  id: proposal.id,
214489
215220
  targetPath: proposal.targetPath,
@@ -214498,17 +215229,17 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214498
215229
  const codeStore = new CodeGraphStore2();
214499
215230
  await codeStore.init(projectDir2);
214500
215231
  const result = await lintKnowledgeWorkspace2({ workspace, claims, codeStore });
214501
- return text(result);
215232
+ return text2(result);
214502
215233
  }
214503
215234
  if (action === "proposal_apply") {
214504
215235
  const proposal = requireText(proposalId, "proposalId");
214505
- if (!proposal) return text({ error: "proposalId is required for proposal_apply." }, true);
215236
+ if (!proposal) return text2({ error: "proposalId is required for proposal_apply." }, true);
214506
215237
  const result = await applyKnowledgeProposal2({
214507
215238
  workspace,
214508
215239
  proposalId: proposal,
214509
215240
  allowManualOverwrite: !!allowManualOverwrite
214510
215241
  });
214511
- return text({
215242
+ return text2({
214512
215243
  proposal: { id: result.proposal.id, status: result.proposal.status },
214513
215244
  targetPath: result.targetPath
214514
215245
  });
@@ -214518,7 +215249,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214518
215249
  const projectRoot = workspace.projectRoot ?? project.rootPath;
214519
215250
  if (action === "workflow_import") {
214520
215251
  const result = await importWindsurfWorkflows2({ workspace, projectRoot });
214521
- return text({
215252
+ return text2({
214522
215253
  imported: result.imported.map((workflow2) => ({
214523
215254
  id: workflow2.id,
214524
215255
  title: workflow2.title,
@@ -214531,7 +215262,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214531
215262
  }
214532
215263
  const synced = await syncCanonicalWorkflows2(workspace);
214533
215264
  if (action === "workflow_list") {
214534
- return text({
215265
+ return text2({
214535
215266
  workflows: workflowStore.listWorkflows(workspace.id).map((workflow2) => ({
214536
215267
  id: workflow2.id,
214537
215268
  title: workflow2.title,
@@ -214546,9 +215277,9 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214546
215277
  }
214547
215278
  if (action === "workflow_select") {
214548
215279
  const selectedTask = requireText(task, "task");
214549
- if (!selectedTask) return text({ error: "task is required for workflow_select." }, true);
215280
+ if (!selectedTask) return text2({ error: "task is required for workflow_select." }, true);
214550
215281
  const result = await selectWorkspaceWorkflows2({ workspace, task: selectedTask });
214551
- return text({
215282
+ return text2({
214552
215283
  selections: result.selections.map((selection) => ({
214553
215284
  id: selection.workflow.id,
214554
215285
  title: selection.workflow.title,
@@ -214560,16 +215291,16 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214560
215291
  });
214561
215292
  }
214562
215293
  const requestedWorkflowId = requireText(workflowId, "workflowId");
214563
- if (!requestedWorkflowId) return text({ error: "workflowId is required for this workflow action." }, true);
215294
+ if (!requestedWorkflowId) return text2({ error: "workflowId is required for this workflow action." }, true);
214564
215295
  const workflow = workflowStore.getWorkflow(requestedWorkflowId);
214565
215296
  if (!workflow || workflow.workspaceId !== workspace.id) {
214566
- return text({ error: "Workflow was not found for this Knowledge Workspace." }, true);
215297
+ return text2({ error: "Workflow was not found for this Knowledge Workspace." }, true);
214567
215298
  }
214568
215299
  if (action === "workflow_preview" || action === "workflow_apply") {
214569
215300
  const targetAgent = requireText(agent, "agent");
214570
- if (!targetAgent) return text({ error: "agent is required for a workflow adapter action." }, true);
215301
+ if (!targetAgent) return text2({ error: "agent is required for a workflow adapter action." }, true);
214571
215302
  const result = action === "workflow_preview" ? await previewWorkflowAdapter2({ workflow, projectRoot, agent: targetAgent }) : await applyWorkflowAdapter2({ workflow, projectRoot, agent: targetAgent });
214572
- return text({
215303
+ return text2({
214573
215304
  workflowId: workflow.id,
214574
215305
  agent: targetAgent,
214575
215306
  status: result.status,
@@ -214580,8 +215311,8 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214580
215311
  }
214581
215312
  if (action === "workflow_run") {
214582
215313
  const runTask = requireText(task, "task");
214583
- if (!runTask) return text({ error: "task is required for workflow_run." }, true);
214584
- if (!outcome) return text({ error: "outcome is required for workflow_run." }, true);
215314
+ if (!runTask) return text2({ error: "task is required for workflow_run." }, true);
215315
+ if (!outcome) return text2({ error: "outcome is required for workflow_run." }, true);
214585
215316
  const result = await recordWorkflowRun2({
214586
215317
  workspace,
214587
215318
  run: {
@@ -214595,14 +215326,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
214595
215326
  selectedEvidence: [...new Set((evidenceIds ?? []).map((item) => item.trim()).filter(Boolean))]
214596
215327
  }
214597
215328
  });
214598
- return text({
215329
+ return text2({
214599
215330
  id: result.id,
214600
215331
  workflowId: result.workflowId,
214601
215332
  outcome: result.outcome,
214602
215333
  verificationVerdict: result.verificationVerdict
214603
215334
  });
214604
215335
  }
214605
- return text({ error: "Unsupported knowledge action." }, true);
215336
+ return text2({ error: "Unsupported knowledge action." }, true);
214606
215337
  }
214607
215338
  );
214608
215339
  server.registerTool(
@@ -216077,10 +216808,10 @@ Ensure the path points to a directory containing a .git folder (or a subdirector
216077
216808
  ];
216078
216809
  const allSkills = await loadMiniSkills2(projectDir2, project.id);
216079
216810
  const miniSkills = allSkills.filter((s3) => {
216080
- const text = `${s3.title}
216811
+ const text2 = `${s3.title}
216081
216812
  ${s3.sourceEntity}
216082
216813
  ${s3.instruction}`.toLowerCase();
216083
- return !SKILL_NOISE.some((p2) => p2.test(text));
216814
+ return !SKILL_NOISE.some((p2) => p2.test(text2));
216084
216815
  });
216085
216816
  if (miniSkills.length > 0) {
216086
216817
  const formatted = formatMiniSkillsForInjection2(miniSkills);
@@ -220084,7 +220815,7 @@ var init_serve_http = __esm({
220084
220815
  },
220085
220816
  run: async ({ args }) => {
220086
220817
  const { createServer: createServer3 } = await import("http");
220087
- const { randomUUID: randomUUID16 } = await import("crypto");
220818
+ const { randomUUID: randomUUID17 } = await import("crypto");
220088
220819
  const { StreamableHTTPServerTransport: StreamableHTTPServerTransport2 } = await Promise.resolve().then(() => (init_streamableHttp(), streamableHttp_exports));
220089
220820
  const { isInitializeRequest: isInitializeRequest2 } = await Promise.resolve().then(() => (init_types8(), types_exports3));
220090
220821
  const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server4(), server_exports2));
@@ -220257,7 +220988,7 @@ var init_serve_http = __esm({
220257
220988
  if (!sessionId && isInitializeRequest2(body)) {
220258
220989
  let createdState = null;
220259
220990
  const transport = new StreamableHTTPServerTransport2({
220260
- sessionIdGenerator: () => randomUUID16(),
220991
+ sessionIdGenerator: () => randomUUID17(),
220261
220992
  enableJsonResponse: true,
220262
220993
  onsessioninitialized: (sid) => {
220263
220994
  if (createdState) sessions.set(sid, createdState);
@@ -221794,21 +222525,21 @@ function isSignificantKnowledge(content) {
221794
222525
  if (!content || typeof content !== "string") {
221795
222526
  return { isSignificant: false, reason: "empty_content", confidence: 1 };
221796
222527
  }
221797
- const text = content.trim();
221798
- const textLower = text.toLowerCase();
222528
+ const text2 = content.trim();
222529
+ const textLower = text2.toLowerCase();
221799
222530
  for (const pattern of SKIP_PATTERNS2) {
221800
- if (pattern.test(text)) {
222531
+ if (pattern.test(text2)) {
221801
222532
  return { isSignificant: false, reason: "skip_pattern", confidence: 0.9 };
221802
222533
  }
221803
222534
  }
221804
222535
  for (const pattern of TECHNICAL_PATTERNS) {
221805
- if (pattern.test(text)) {
222536
+ if (pattern.test(text2)) {
221806
222537
  return { isSignificant: true, reason: "technical_pattern", confidence: 0.85 };
221807
222538
  }
221808
222539
  }
221809
222540
  let codePatternMatches = 0;
221810
222541
  for (const pattern of CODE_PATTERNS) {
221811
- if (pattern.test(text)) {
222542
+ if (pattern.test(text2)) {
221812
222543
  codePatternMatches++;
221813
222544
  }
221814
222545
  }
@@ -221828,14 +222559,14 @@ function isSignificantKnowledge(content) {
221828
222559
  return { isSignificant: true, reason: "moderate_technical_density", confidence: 0.6 };
221829
222560
  }
221830
222561
  }
221831
- if (text.length > 200) {
222562
+ if (text2.length > 200) {
221832
222563
  return { isSignificant: true, reason: "substantial_length", confidence: 0.5 };
221833
222564
  }
221834
222565
  return { isSignificant: false, reason: "no_technical_indicators", confidence: 0.6 };
221835
222566
  }
221836
222567
  function isRetrievedResult(content) {
221837
222568
  if (!content || typeof content !== "string") return false;
221838
- const text = content.toLowerCase();
222569
+ const text2 = content.toLowerCase();
221839
222570
  const retrievedPatterns = [
221840
222571
  /^(memorix_search|memorix_detail|memorix_timeline|search_nodes|read_graph):/i,
221841
222572
  /^(retrieved|result|results|found|matches|nodes|edges|search completed):/i,
@@ -221844,7 +222575,7 @@ function isRetrievedResult(content) {
221844
222575
  /^(totalresults:|searchtime:|tokens:)/i
221845
222576
  ];
221846
222577
  for (const pattern of retrievedPatterns) {
221847
- if (pattern.test(text)) {
222578
+ if (pattern.test(text2)) {
221848
222579
  return true;
221849
222580
  }
221850
222581
  }
@@ -224085,25 +224816,25 @@ function inferType(subject, body) {
224085
224816
  perf: "trade-off"
224086
224817
  };
224087
224818
  if (prefixMap[prefix]) return prefixMap[prefix];
224088
- const text = `${subject} ${body}`.toLowerCase();
224089
- if (/\b(fix|bug|crash|error|issue|hotfix|patch)\b/.test(text)) return "problem-solution";
224090
- if (/\b(feat|feature|add|implement|new)\b/.test(text)) return "what-changed";
224091
- if (/\b(refactor|clean|restructure|reorganize)\b/.test(text)) return "what-changed";
224092
- if (/\b(chore|bump|version|release|publish)\b/.test(text)) return "what-changed";
224093
- if (/\b(doc|readme|changelog)\b/.test(text)) return "how-it-works";
224094
- if (/\b(test|spec|e2e|coverage)\b/.test(text)) return "discovery";
224095
- if (/\b(ci|cd|workflow|deploy|docker)\b/.test(text)) return "what-changed";
224096
- if (/\b(security|vulnerability|cve)\b/.test(text)) return "gotcha";
224097
- if (/\b(revert|rollback)\b/.test(text)) return "problem-solution";
224098
- if (/\b(deprecat|remove|drop)\b/.test(text)) return "decision";
224099
- if (/\b(perf|optim|speed|cache)\b/.test(text)) return "trade-off";
224819
+ const text2 = `${subject} ${body}`.toLowerCase();
224820
+ if (/\b(fix|bug|crash|error|issue|hotfix|patch)\b/.test(text2)) return "problem-solution";
224821
+ if (/\b(feat|feature|add|implement|new)\b/.test(text2)) return "what-changed";
224822
+ if (/\b(refactor|clean|restructure|reorganize)\b/.test(text2)) return "what-changed";
224823
+ if (/\b(chore|bump|version|release|publish)\b/.test(text2)) return "what-changed";
224824
+ if (/\b(doc|readme|changelog)\b/.test(text2)) return "how-it-works";
224825
+ if (/\b(test|spec|e2e|coverage)\b/.test(text2)) return "discovery";
224826
+ if (/\b(ci|cd|workflow|deploy|docker)\b/.test(text2)) return "what-changed";
224827
+ if (/\b(security|vulnerability|cve)\b/.test(text2)) return "gotcha";
224828
+ if (/\b(revert|rollback)\b/.test(text2)) return "problem-solution";
224829
+ if (/\b(deprecat|remove|drop)\b/.test(text2)) return "decision";
224830
+ if (/\b(perf|optim|speed|cache)\b/.test(text2)) return "trade-off";
224100
224831
  return "what-changed";
224101
224832
  }
224102
224833
  function extractConcepts(commit) {
224103
224834
  const concepts = [];
224104
- const text = `${commit.subject} ${commit.body}`;
224835
+ const text2 = `${commit.subject} ${commit.body}`;
224105
224836
  const techPatterns = /\b(react|vue|angular|express|fastify|redis|postgres|mysql|docker|nginx|webpack|vite|tsup|vitest|jest)\b/gi;
224106
- for (const match2 of text.matchAll(techPatterns)) {
224837
+ for (const match2 of text2.matchAll(techPatterns)) {
224107
224838
  concepts.push(match2[0].toLowerCase());
224108
224839
  }
224109
224840
  const scopeMatch = commit.subject.match(/^\w+\(([^)]+)\)/);
@@ -224172,26 +224903,26 @@ function isAllFilesNoise(files, extraPatterns) {
224172
224903
  );
224173
224904
  }
224174
224905
  function matchesGlob(file2, pattern) {
224175
- const text = file2.replace(/\\/g, "/");
224906
+ const text2 = file2.replace(/\\/g, "/");
224176
224907
  const glob = pattern.replace(/\\/g, "/");
224177
224908
  if (!glob) return false;
224178
- let previous = new Array(text.length + 1).fill(false);
224909
+ let previous = new Array(text2.length + 1).fill(false);
224179
224910
  previous[0] = true;
224180
224911
  for (const token of glob) {
224181
- const current = new Array(text.length + 1).fill(false);
224912
+ const current = new Array(text2.length + 1).fill(false);
224182
224913
  if (token === "*") {
224183
224914
  current[0] = previous[0];
224184
- for (let index = 1; index <= text.length; index++) {
224915
+ for (let index = 1; index <= text2.length; index++) {
224185
224916
  current[index] = previous[index] || current[index - 1];
224186
224917
  }
224187
224918
  } else {
224188
- for (let index = 1; index <= text.length; index++) {
224189
- current[index] = previous[index - 1] && (token === "?" || token === text[index - 1]);
224919
+ for (let index = 1; index <= text2.length; index++) {
224920
+ current[index] = previous[index - 1] && (token === "?" || token === text2[index - 1]);
224190
224921
  }
224191
224922
  }
224192
224923
  previous = current;
224193
224924
  }
224194
- return previous[text.length];
224925
+ return previous[text2.length];
224195
224926
  }
224196
224927
  function shouldFilterCommit(commit, config2) {
224197
224928
  const skipMerge = config2?.skipMergeCommits ?? true;
@@ -226449,8 +227180,8 @@ async function inspectPlugin(agent, scope) {
226449
227180
  };
226450
227181
  }
226451
227182
  function looksLikeStaleMemorixCommand(server) {
226452
- const text = [server.command, ...server.args ?? []].join(" ");
226453
- return /[\\/]\.worktrees[\\/]/i.test(text) || /[\\/]dist[\\/]cli[\\/]index\.js/i.test(text);
227183
+ const text2 = [server.command, ...server.args ?? []].join(" ");
227184
+ return /[\\/]\.worktrees[\\/]/i.test(text2) || /[\\/]dist[\\/]cli[\\/]index\.js/i.test(text2);
226454
227185
  }
226455
227186
  function isRecommendedStdioServer(server) {
226456
227187
  const commandBase = basename5(server.command).toLowerCase().replace(/\.(cmd|ps1|exe)$/i, "");
@@ -227611,12 +228342,12 @@ function isLowQuality(title) {
227611
228342
  return LOW_QUALITY_PATTERNS.some((p2) => p2.test(title.trim()));
227612
228343
  }
227613
228344
  function isNoisePollution(obs) {
227614
- const text = [obs.title, obs.narrative, obs.entityName, ...obs.facts ?? [], ...obs.concepts ?? []].filter(Boolean).join("\n");
228345
+ const text2 = [obs.title, obs.narrative, obs.entityName, ...obs.facts ?? [], ...obs.concepts ?? []].filter(Boolean).join("\n");
227615
228346
  for (const p2 of SYSTEM_SELF_PATTERNS2) {
227616
- if (p2.test(text)) return { isNoise: true, reason: "system-self" };
228347
+ if (p2.test(text2)) return { isNoise: true, reason: "system-self" };
227617
228348
  }
227618
228349
  for (const p2 of NOISE_PATTERNS3) {
227619
- if (p2.test(text)) return { isNoise: true, reason: "demo/test/noise" };
228350
+ if (p2.test(text2)) return { isNoise: true, reason: "demo/test/noise" };
227620
228351
  }
227621
228352
  return { isNoise: false, reason: "" };
227622
228353
  }
@@ -228333,8 +229064,8 @@ var init_ring_buffer = __esm({
228333
229064
  }
228334
229065
  maxLines;
228335
229066
  lines = [];
228336
- push(text) {
228337
- for (const line of text.split("\n")) {
229067
+ push(text2) {
229068
+ for (const line of text2.split("\n")) {
228338
229069
  if (line.trim()) {
228339
229070
  this.lines.push(line);
228340
229071
  if (this.lines.length > this.maxLines) this.lines.shift();
@@ -228431,9 +229162,9 @@ function spawnAgentWithStream(command, args, opts, stdinData, onStdoutLine, onCo
228431
229162
  };
228432
229163
  let stdoutPartial = "";
228433
229164
  child.stdout?.on("data", (chunk) => {
228434
- const text = chunk.toString();
228435
- ring.push(text);
228436
- stdoutPartial += text;
229165
+ const text2 = chunk.toString();
229166
+ ring.push(text2);
229167
+ stdoutPartial += text2;
228437
229168
  const lines = stdoutPartial.split("\n");
228438
229169
  stdoutPartial = lines.pop() ?? "";
228439
229170
  for (const line of lines) {
@@ -229833,7 +230564,7 @@ function resetBackoff(taskId) {
229833
230564
  }
229834
230565
  function classifyError(ctx, taskId) {
229835
230566
  const { exitCode, killed, tailOutput, hasEndTurn } = ctx;
229836
- const text = tailOutput.slice(-2e3);
230567
+ const text2 = tailOutput.slice(-2e3);
229837
230568
  if (!killed && exitCode !== 0 && hasEndTurn === false) {
229838
230569
  return {
229839
230570
  category: "truncated",
@@ -229843,7 +230574,7 @@ function classifyError(ctx, taskId) {
229843
230574
  continuationPrompt: "Your previous output was truncated due to output limits. Continue from where you stopped. Do not repeat what you already wrote."
229844
230575
  };
229845
230576
  }
229846
- if (matchesAny(text, TRUNCATED_PATTERNS)) {
230577
+ if (matchesAny(text2, TRUNCATED_PATTERNS)) {
229847
230578
  return {
229848
230579
  category: "truncated",
229849
230580
  strategy: "continue",
@@ -229852,7 +230583,7 @@ function classifyError(ctx, taskId) {
229852
230583
  continuationPrompt: "Your previous output was truncated due to output limits. Continue from where you stopped. Do not repeat what you already wrote."
229853
230584
  };
229854
230585
  }
229855
- if (matchesAny(text, CONTEXT_OVERFLOW_PATTERNS)) {
230586
+ if (matchesAny(text2, CONTEXT_OVERFLOW_PATTERNS)) {
229856
230587
  return {
229857
230588
  category: "context_overflow",
229858
230589
  strategy: "compact_and_retry",
@@ -229860,7 +230591,7 @@ function classifyError(ctx, taskId) {
229860
230591
  reason: "Context overflow detected \u2014 prompt is too large for the model"
229861
230592
  };
229862
230593
  }
229863
- if (matchesAny(text, TRANSIENT_PATTERNS)) {
230594
+ if (matchesAny(text2, TRANSIENT_PATTERNS)) {
229864
230595
  const attempt = taskId ? (backoffState.get(taskId) ?? 0) + 1 : 1;
229865
230596
  if (taskId) backoffState.set(taskId, attempt);
229866
230597
  const baseDelay = 2e3;
@@ -229883,8 +230614,8 @@ function classifyError(ctx, taskId) {
229883
230614
  reason: killed ? "Agent killed by timeout" : `Agent exited with code ${exitCode}`
229884
230615
  };
229885
230616
  }
229886
- function matchesAny(text, patterns) {
229887
- return patterns.some((p2) => p2.test(text));
230617
+ function matchesAny(text2, patterns) {
230618
+ return patterns.some((p2) => p2.test(text2));
229888
230619
  }
229889
230620
  var TRUNCATED_PATTERNS, CONTEXT_OVERFLOW_PATTERNS, TRANSIENT_PATTERNS, backoffState;
229890
230621
  var init_error_recovery = __esm({
@@ -230422,8 +231153,8 @@ function storePipelineSummary(opts) {
230422
231153
  }
230423
231154
  })();
230424
231155
  }
230425
- function sanitizeErrorPattern(text) {
230426
- return text.replace(/[A-Z]:\\(?:[\w.-]+\\)+/gi, "./").replace(/\/(?:home|Users|var|tmp|opt)\/[\w.-]+\//g, "./").replace(/:(\d+):(\d+)/g, ":_:_").replace(/\bline\s+\d+/gi, "line _").replace(/node_modules\/[^\s]+/g, "node_modules/...");
231156
+ function sanitizeErrorPattern(text2) {
231157
+ return text2.replace(/[A-Z]:\\(?:[\w.-]+\\)+/gi, "./").replace(/\/(?:home|Users|var|tmp|opt)\/[\w.-]+\//g, "./").replace(/:(\d+):(\d+)/g, ":_:_").replace(/\bline\s+\d+/gi, "line _").replace(/node_modules\/[^\s]+/g, "node_modules/...");
230427
231158
  }
230428
231159
  function hashErrorPattern(errorOutput) {
230429
231160
  const sanitized = sanitizeErrorPattern(errorOutput).slice(0, 500);
@@ -231958,7 +232689,7 @@ var init_theme = __esm({
231958
232689
  check: "[OK]",
231959
232690
  cross: "[ERROR]",
231960
232691
  info: "[i]",
231961
- pill: (text) => `[${text}]`
232692
+ pill: (text2) => `[${text2}]`
231962
232693
  };
231963
232694
  EDGE_SYMBOLS = {
231964
232695
  supports: "->",
@@ -232086,27 +232817,27 @@ function isFullwidth(ch) {
232086
232817
  if (cp >= 128512 && cp <= 129535) return true;
232087
232818
  return false;
232088
232819
  }
232089
- function previousCursorPos(text, cursorPos) {
232820
+ function previousCursorPos(text2, cursorPos) {
232090
232821
  let start = 0;
232091
- for (const ch of text) {
232822
+ for (const ch of text2) {
232092
232823
  const end = start + ch.length;
232093
232824
  if (end >= cursorPos) return start;
232094
232825
  start = end;
232095
232826
  }
232096
232827
  return 0;
232097
232828
  }
232098
- function nextCursorPos(text, cursorPos) {
232829
+ function nextCursorPos(text2, cursorPos) {
232099
232830
  let start = 0;
232100
- for (const ch of text) {
232831
+ for (const ch of text2) {
232101
232832
  const end = start + ch.length;
232102
232833
  if (start >= cursorPos) return end;
232103
232834
  if (end > cursorPos) return end;
232104
232835
  start = end;
232105
232836
  }
232106
- return text.length;
232837
+ return text2.length;
232107
232838
  }
232108
- function getCharacterAt(text, cursorPos) {
232109
- const codePoint = text.codePointAt(cursorPos);
232839
+ function getCharacterAt(text2, cursorPos) {
232840
+ const codePoint = text2.codePointAt(cursorPos);
232110
232841
  return codePoint === void 0 ? "" : String.fromCodePoint(codePoint);
232111
232842
  }
232112
232843
  function CommandBar({
@@ -232336,9 +233067,9 @@ import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-run
232336
233067
  function separator(width = 50) {
232337
233068
  return SEP.thin.repeat(width);
232338
233069
  }
232339
- function truncate2(text, max = 60) {
232340
- if (text.length <= max) return text;
232341
- return `${text.slice(0, max)}\u2026`;
233070
+ function truncate2(text2, max = 60) {
233071
+ if (text2.length <= max) return text2;
233072
+ return `${text2.slice(0, max)}\u2026`;
232342
233073
  }
232343
233074
  function RecentView({ recentMemories, loading }) {
232344
233075
  const filtered = recentMemories.filter((memory) => !DEV_NOISE_PATTERNS.some((pattern) => pattern.test(memory.title)));
@@ -233270,9 +234001,9 @@ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
233270
234001
  function separator4(width = 50) {
233271
234002
  return SEP.thin.repeat(width);
233272
234003
  }
233273
- function truncate3(text, max = 80) {
233274
- if (text.length <= max) return text;
233275
- return `${text.slice(0, max)}...`;
234004
+ function truncate3(text2, max = 80) {
234005
+ if (text2.length <= max) return text2;
234006
+ return `${text2.slice(0, max)}...`;
233276
234007
  }
233277
234008
  function KnowledgeView({ knowledge, loading, selectedItemIdx, itemCount }) {
233278
234009
  if (loading) {
@@ -233466,9 +234197,9 @@ function formatEmbeddingLabel(status, providerName) {
233466
234197
  if (providerName) return "Local ready";
233467
234198
  return "Ready";
233468
234199
  }
233469
- function truncate4(text, max = 60) {
233470
- if (text.length <= max) return text;
233471
- return `${text.slice(0, max)}...`;
234200
+ function truncate4(text2, max = 60) {
234201
+ if (text2.length <= max) return text2;
234202
+ return `${text2.slice(0, max)}...`;
233472
234203
  }
233473
234204
  async function getProjectInfo() {
233474
234205
  try {
@@ -233626,7 +234357,7 @@ async function searchMemories(query, limit2 = 10) {
233626
234357
  return [];
233627
234358
  }
233628
234359
  }
233629
- async function storeQuickMemory(text) {
234360
+ async function storeQuickMemory(text2) {
233630
234361
  try {
233631
234362
  const { initObservations: initObservations2, storeObservation: storeObservation2 } = await Promise.resolve().then(() => (init_observations(), observations_exports));
233632
234363
  const { initObservationStore: initObservationStore2 } = await Promise.resolve().then(() => (init_obs_store(), obs_store_exports));
@@ -233636,15 +234367,15 @@ async function storeQuickMemory(text) {
233636
234367
  const result = await storeObservation2({
233637
234368
  entityName: "quick-note",
233638
234369
  type: "discovery",
233639
- title: text.slice(0, 100),
233640
- narrative: text,
234370
+ title: text2.slice(0, 100),
234371
+ narrative: text2,
233641
234372
  facts: [],
233642
234373
  projectId: proj.id,
233643
234374
  sourceDetail: "explicit",
233644
234375
  visibilityReader: reader,
233645
234376
  ...identity ? { createdByAgentId: identity.agentId } : {}
233646
234377
  });
233647
- return { id: result.observation.id, title: text.slice(0, 100) };
234378
+ return { id: result.observation.id, title: text2.slice(0, 100) };
233648
234379
  } catch {
233649
234380
  return null;
233650
234381
  }
@@ -233842,9 +234573,9 @@ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
233842
234573
  function separator5(width = 50) {
233843
234574
  return SEP.thin.repeat(width);
233844
234575
  }
233845
- function truncate5(text, max = 60) {
233846
- if (text.length <= max) return text;
233847
- return `${text.slice(0, max)}...`;
234576
+ function truncate5(text2, max = 60) {
234577
+ if (text2.length <= max) return text2;
234578
+ return `${text2.slice(0, max)}...`;
233848
234579
  }
233849
234580
  function MemoryView({ projectId, focusRefId, selectedIdx, onNavigateKnowledge, inputFocused }) {
233850
234581
  const [mode, setMode] = useState3("browse");
@@ -234045,9 +234776,9 @@ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
234045
234776
  function separator6(width) {
234046
234777
  return SEP.thin.repeat(Math.max(12, Math.min(width, 72)));
234047
234778
  }
234048
- function truncate6(text, max) {
234049
- if (text.length <= max) return text;
234050
- return `${text.slice(0, max - 1)}\u2026`;
234779
+ function truncate6(text2, max) {
234780
+ if (text2.length <= max) return text2;
234781
+ return `${text2.slice(0, max - 1)}\u2026`;
234051
234782
  }
234052
234783
  function displayWidth(str3) {
234053
234784
  let w3 = 0;
@@ -234061,12 +234792,12 @@ function displayWidth(str3) {
234061
234792
  }
234062
234793
  return w3;
234063
234794
  }
234064
- function cjkAwareLines(text, maxCols) {
234065
- if (maxCols < 4) return [text];
234795
+ function cjkAwareLines(text2, maxCols) {
234796
+ if (maxCols < 4) return [text2];
234066
234797
  const lines = [];
234067
234798
  let line = "";
234068
234799
  let lineW = 0;
234069
- for (const ch of text) {
234800
+ for (const ch of text2) {
234070
234801
  if (ch === "\n") {
234071
234802
  lines.push(line);
234072
234803
  line = "";
@@ -234224,9 +234955,9 @@ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
234224
234955
  function separator7(width = 50) {
234225
234956
  return SEP.thin.repeat(width);
234226
234957
  }
234227
- function truncate7(text, max = 80) {
234228
- if (text.length <= max) return text;
234229
- return `${text.slice(0, max)}...`;
234958
+ function truncate7(text2, max = 80) {
234959
+ if (text2.length <= max) return text2;
234960
+ return `${text2.slice(0, max)}...`;
234230
234961
  }
234231
234962
  function WorkbenchView({ project, contentWidth, viewportHeight, inputFocused }) {
234232
234963
  const MAX_CHAT_MESSAGES = 100;
@@ -234314,12 +235045,12 @@ function WorkbenchView({ project, contentWidth, viewportHeight, inputFocused })
234314
235045
  });
234315
235046
  try {
234316
235047
  const result = await askMemoryQuestionStream(trimmed, history, {
234317
- onChunk: (text) => {
235048
+ onChunk: (text2) => {
234318
235049
  setChatMessages((prev) => {
234319
235050
  const updated = [...prev];
234320
235051
  const lastIdx = updated.length - 1;
234321
235052
  if (lastIdx >= 0 && updated[lastIdx].role === "assistant") {
234322
- updated[lastIdx] = { ...updated[lastIdx], content: updated[lastIdx].content + text };
235053
+ updated[lastIdx] = { ...updated[lastIdx], content: updated[lastIdx].content + text2 };
234323
235054
  }
234324
235055
  return updated;
234325
235056
  });
@@ -234458,9 +235189,9 @@ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
234458
235189
  function separator8(width = 50) {
234459
235190
  return SEP.thin.repeat(width);
234460
235191
  }
234461
- function truncate8(text, max = 80) {
234462
- if (text.length <= max) return text;
234463
- return `${text.slice(0, max)}...`;
235192
+ function truncate8(text2, max = 80) {
235193
+ if (text2.length <= max) return text2;
235194
+ return `${text2.slice(0, max)}...`;
234464
235195
  }
234465
235196
  function GraphView({ projectId, inputFocused, onNavigateKnowledge }) {
234466
235197
  const [graph, setGraph] = useState5(null);
@@ -234779,18 +235510,18 @@ function charWidth(ch) {
234779
235510
  const cp = ch.codePointAt(0);
234780
235511
  return cp >= 19968 && cp <= 40959 || cp >= 12352 && cp <= 12543 || cp >= 44032 && cp <= 55215 || cp >= 65281 && cp <= 65376 || cp >= 13312 && cp <= 19903 ? 2 : 1;
234781
235512
  }
234782
- function fit(text, max) {
235513
+ function fit(text2, max) {
234783
235514
  if (max <= 0) return "";
234784
235515
  let w3 = 0;
234785
- for (const ch of text) {
235516
+ for (const ch of text2) {
234786
235517
  w3 += charWidth(ch);
234787
235518
  if (w3 > max) break;
234788
235519
  }
234789
- if (w3 <= max) return text.padEnd(text.length + (max - w3));
235520
+ if (w3 <= max) return text2.padEnd(text2.length + (max - w3));
234790
235521
  if (max === 1) return "\u2026";
234791
235522
  let result = "";
234792
235523
  let rw = 0;
234793
- for (const ch of text) {
235524
+ for (const ch of text2) {
234794
235525
  const cw = charWidth(ch);
234795
235526
  if (rw + cw > max - 1) break;
234796
235527
  result += ch;
@@ -234866,9 +235597,9 @@ __export(chat_store_exports, {
234866
235597
  ChatTranscriptStore: () => ChatTranscriptStore,
234867
235598
  getChatStore: () => getChatStore
234868
235599
  });
234869
- function safeJsonParse4(text, fallback) {
235600
+ function safeJsonParse4(text2, fallback) {
234870
235601
  try {
234871
- return JSON.parse(text);
235602
+ return JSON.parse(text2);
234872
235603
  } catch {
234873
235604
  return fallback;
234874
235605
  }
@@ -235228,12 +235959,12 @@ function WorkbenchApp({ version: version2, onExitForInteractive }) {
235228
235959
  });
235229
235960
  try {
235230
235961
  const result = await askMemoryQuestionStream(trimmed, history, {
235231
- onChunk: (text) => {
235962
+ onChunk: (text2) => {
235232
235963
  setChatMessages((prev) => {
235233
235964
  const updated = [...prev];
235234
235965
  const lastIdx = updated.length - 1;
235235
235966
  if (lastIdx >= 0 && updated[lastIdx].role === "assistant") {
235236
- updated[lastIdx] = { ...updated[lastIdx], content: updated[lastIdx].content + text };
235967
+ updated[lastIdx] = { ...updated[lastIdx], content: updated[lastIdx].content + text2 };
235237
235968
  }
235238
235969
  return updated;
235239
235970
  });
@@ -235984,11 +236715,11 @@ ${hookScript}`, "utf-8");
235984
236715
  };
235985
236716
  const renderOverlayContent = () => {
235986
236717
  if (!overlayView) return null;
235987
- const fitInline = (text, max) => {
236718
+ const fitInline = (text2, max) => {
235988
236719
  if (max <= 0) return "";
235989
- if (text.length <= max) return text;
236720
+ if (text2.length <= max) return text2;
235990
236721
  if (max === 1) return ".";
235991
- return `${text.slice(0, max - 1)}.`;
236722
+ return `${text2.slice(0, max - 1)}.`;
235992
236723
  };
235993
236724
  switch (overlayView) {
235994
236725
  case "chat":