memorix 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/TEAM.md +86 -86
  3. package/dist/cli/index.js +211 -69
  4. package/dist/cli/memcode.js +0 -0
  5. package/dist/index.js +211 -69
  6. package/dist/maintenance-runner.js +169 -37
  7. package/dist/media-audio-runner.js +169 -37
  8. package/dist/media-video-runner.js +169 -37
  9. package/dist/memcode-runtime/CHANGELOG.md +14 -0
  10. package/dist/sdk.js +210 -68
  11. package/dist/types.d.ts +2 -0
  12. package/dist/vector-backfill-runner.js +169 -37
  13. package/docs/DESIGN_DECISIONS.md +357 -357
  14. package/package.json +1 -1
  15. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  16. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  17. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  18. package/plugins/copilot/memorix/plugin.json +1 -1
  19. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  20. package/plugins/omp/memorix/package.json +1 -1
  21. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  22. package/plugins/pi/memorix/package.json +1 -1
  23. package/server.json +2 -2
  24. package/src/audit/index.ts +156 -156
  25. package/src/cli/commands/formation.ts +48 -48
  26. package/src/cli/commands/git-hook-install.ts +111 -111
  27. package/src/cli/commands/handoff.ts +54 -54
  28. package/src/cli/commands/hooks-status.ts +63 -63
  29. package/src/cli/commands/ingest.ts +44 -44
  30. package/src/cli/commands/integrate-shared.ts +15 -15
  31. package/src/cli/commands/lock.ts +82 -82
  32. package/src/cli/commands/message.ts +104 -104
  33. package/src/cli/commands/poll.ts +58 -58
  34. package/src/cli/commands/reasoning.ts +118 -118
  35. package/src/cli/commands/skills.ts +114 -114
  36. package/src/cli/commands/task.ts +167 -167
  37. package/src/cli/commands/transfer.ts +47 -47
  38. package/src/cli/index.ts +406 -406
  39. package/src/cli/tui/ChatView.tsx +234 -234
  40. package/src/cli/tui/CommandBar.tsx +312 -312
  41. package/src/cli/tui/ContextRail.tsx +118 -118
  42. package/src/cli/tui/HeaderBar.tsx +72 -72
  43. package/src/cli/tui/LogoBanner.tsx +51 -51
  44. package/src/cli/tui/index.ts +41 -41
  45. package/src/cli/version.ts +7 -7
  46. package/src/cli/workbench.ts +1 -1
  47. package/src/dashboard/project-classification.ts +64 -64
  48. package/src/embedding/api-provider.ts +105 -22
  49. package/src/embedding/provider.ts +2 -0
  50. package/src/git/hooks-path.ts +85 -85
  51. package/src/hooks/pattern-detector.ts +173 -173
  52. package/src/hooks/significance-filter.ts +250 -250
  53. package/src/llm/memory-manager.ts +328 -328
  54. package/src/llm/provider.ts +17 -8
  55. package/src/llm/quality.ts +248 -248
  56. package/src/memory/attribution-guard.ts +249 -249
  57. package/src/memory/disclosure-policy.ts +135 -135
  58. package/src/memory/entity-extractor.ts +197 -197
  59. package/src/memory/formation/evaluate.ts +217 -217
  60. package/src/memory/formation/extract.ts +6 -3
  61. package/src/memory/formation/index.ts +2 -1
  62. package/src/memory/formation/resolve.ts +10 -6
  63. package/src/memory/formation/types.ts +3 -1
  64. package/src/memory/freshness.ts +122 -122
  65. package/src/memory/graph.ts +197 -197
  66. package/src/memory/long-term.ts +7 -1
  67. package/src/memory/refs.ts +94 -94
  68. package/src/memory/secret-filter.ts +79 -79
  69. package/src/orchestrate/adapters/claude-stream.ts +192 -192
  70. package/src/orchestrate/adapters/claude.ts +111 -111
  71. package/src/orchestrate/adapters/codex-stream.ts +134 -134
  72. package/src/orchestrate/adapters/codex.ts +41 -41
  73. package/src/orchestrate/adapters/gemini-stream.ts +166 -166
  74. package/src/orchestrate/adapters/gemini.ts +42 -42
  75. package/src/orchestrate/adapters/index.ts +73 -73
  76. package/src/orchestrate/adapters/opencode-stream.ts +143 -143
  77. package/src/orchestrate/adapters/opencode.ts +47 -47
  78. package/src/orchestrate/adapters/types.ts +77 -77
  79. package/src/orchestrate/capability-router.ts +284 -284
  80. package/src/orchestrate/cost-tracker.ts +219 -219
  81. package/src/orchestrate/error-recovery.ts +191 -191
  82. package/src/orchestrate/evidence.ts +140 -140
  83. package/src/orchestrate/ledger.ts +110 -110
  84. package/src/orchestrate/memorix-bridge.ts +343 -343
  85. package/src/orchestrate/output-budget.ts +80 -80
  86. package/src/orchestrate/permission.ts +152 -152
  87. package/src/orchestrate/pipeline-trace.ts +131 -131
  88. package/src/orchestrate/prompt-builder.ts +155 -155
  89. package/src/orchestrate/ring-buffer.ts +37 -37
  90. package/src/orchestrate/task-graph.ts +389 -389
  91. package/src/project/aliases.ts +374 -374
  92. package/src/rules/adapters/trae.ts +56 -56
  93. package/src/rules/syncer.ts +235 -235
  94. package/src/search/query-expansion.ts +52 -52
  95. package/src/server/formation-timeout.ts +27 -27
  96. package/src/server.ts +14 -10
  97. package/src/skills/mini-skills.ts +386 -386
  98. package/src/store/chat-store.ts +119 -119
  99. package/src/store/graph-store.ts +249 -249
  100. package/src/store/mini-skill-store.ts +349 -349
  101. package/src/store/orama-store.ts +6 -4
  102. package/src/store/persistence-json.ts +212 -212
  103. package/src/store/persistence.ts +291 -291
  104. package/src/store/project-affinity.ts +195 -195
  105. package/src/team/event-bus.ts +76 -76
  106. package/src/team/handoff.ts +161 -161
  107. package/src/team/poll.ts +132 -132
  108. package/src/timeout.ts +67 -0
  109. package/src/types.ts +2 -0
  110. package/src/workspace/mcp-adapters/codex.ts +191 -191
  111. package/src/workspace/mcp-adapters/copilot.ts +105 -105
  112. package/src/workspace/mcp-adapters/cursor.ts +53 -53
  113. package/src/workspace/mcp-adapters/kiro.ts +64 -64
  114. package/src/workspace/mcp-adapters/opencode.ts +123 -123
  115. package/src/workspace/mcp-adapters/trae.ts +134 -134
  116. package/src/workspace/mcp-adapters/windsurf.ts +91 -91
  117. package/src/workspace/sanitizer.ts +60 -60
package/dist/cli/index.js CHANGED
@@ -3221,7 +3221,7 @@ ${import_picocolors.default.gray(m3)} ${s4}
3221
3221
 
3222
3222
  // src/cli/version.ts
3223
3223
  function getCliVersion() {
3224
- return true ? "1.5.0" : pkg.version;
3224
+ return true ? "1.5.1" : pkg.version;
3225
3225
  }
3226
3226
  var init_version = __esm({
3227
3227
  "src/cli/version.ts"() {
@@ -22327,6 +22327,8 @@ function getPreferredBatchSize(config2) {
22327
22327
  }
22328
22328
  function parseBatchLimit(error40) {
22329
22329
  if (!(error40 instanceof Error)) return null;
22330
+ const status = error40 instanceof EmbeddingAPIError ? error40.status : Number(error40.message.match(/Embedding API error \((\d{3})\)/i)?.[1] ?? 0);
22331
+ if (status > 0 && status !== 400) return null;
22330
22332
  const explicit = error40.message.match(/should not be larger than\s+(\d+)/i);
22331
22333
  if (explicit) return parseInt(explicit[1], 10);
22332
22334
  if (/batch size/i.test(error40.message)) {
@@ -22339,37 +22341,99 @@ async function fetchWithRetry(url2, apiKey, body, options = {}, attempt = 0, nat
22339
22341
  const controller = new AbortController();
22340
22342
  const timeoutMs = typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) ? Math.max(100, Math.min(Math.floor(options.timeoutMs), 6e4)) : 1e4;
22341
22343
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
22344
+ const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
22342
22345
  let response;
22343
22346
  try {
22344
22347
  response = await fetch(url2, {
22345
22348
  method: "POST",
22346
22349
  headers: nativeGemini ? { "Content-Type": "application/json", "x-goog-api-key": apiKey } : { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
22347
22350
  body: JSON.stringify(body),
22348
- signal: controller.signal
22351
+ signal
22349
22352
  });
22350
22353
  } catch (err) {
22351
22354
  clearTimeout(timeout);
22352
- if (err instanceof Error && err.name === "AbortError") {
22355
+ if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
22353
22356
  throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url2}`);
22354
22357
  }
22355
22358
  throw err;
22356
22359
  }
22357
- clearTimeout(timeout);
22358
- if (response.ok) {
22359
- return response.json();
22360
+ try {
22361
+ if (response.ok) {
22362
+ return await raceWithAbort(
22363
+ response.json(),
22364
+ signal
22365
+ );
22366
+ }
22367
+ if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
22368
+ const delay2 = BASE_DELAY_MS * Math.pow(2, attempt);
22369
+ const retryAfter = response.headers.get("retry-after");
22370
+ const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
22371
+ const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay2;
22372
+ console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
22373
+ await waitForRetry(waitMs, options.signal);
22374
+ return fetchWithRetry(url2, apiKey, body, options, attempt + 1, nativeGemini);
22375
+ }
22376
+ const errorText2 = await raceWithAbort(
22377
+ response.text().catch(() => "unknown error"),
22378
+ signal
22379
+ );
22380
+ throw new EmbeddingAPIError(response.status, errorText2);
22381
+ } catch (err) {
22382
+ if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
22383
+ throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url2}`);
22384
+ }
22385
+ throw err;
22386
+ } finally {
22387
+ clearTimeout(timeout);
22360
22388
  }
22361
- if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
22362
- const delay2 = BASE_DELAY_MS * Math.pow(2, attempt);
22363
- const retryAfter = response.headers.get("retry-after");
22364
- const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1e3 : delay2;
22365
- console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
22389
+ }
22390
+ function abortError() {
22391
+ const error40 = new Error("Embedding API request aborted");
22392
+ error40.name = "AbortError";
22393
+ return error40;
22394
+ }
22395
+ function raceWithAbort(promise2, signal) {
22396
+ if (signal.aborted) return Promise.reject(abortError());
22397
+ return new Promise((resolve6, reject) => {
22398
+ const onAbort = () => {
22399
+ signal.removeEventListener("abort", onAbort);
22400
+ reject(abortError());
22401
+ };
22402
+ signal.addEventListener("abort", onAbort, { once: true });
22403
+ promise2.then(
22404
+ (value) => {
22405
+ signal.removeEventListener("abort", onAbort);
22406
+ resolve6(value);
22407
+ },
22408
+ (error40) => {
22409
+ signal.removeEventListener("abort", onAbort);
22410
+ reject(error40);
22411
+ }
22412
+ );
22413
+ });
22414
+ }
22415
+ async function waitForRetry(waitMs, signal) {
22416
+ if (!signal) {
22366
22417
  await new Promise((resolve6) => setTimeout(resolve6, waitMs));
22367
- return fetchWithRetry(url2, apiKey, body, options, attempt + 1, nativeGemini);
22418
+ return;
22368
22419
  }
22369
- const errorText2 = await response.text().catch(() => "unknown error");
22370
- throw new Error(`Embedding API error (${response.status}): ${errorText2}`);
22420
+ const abortSignal = signal;
22421
+ if (abortSignal.aborted) throw new Error("Embedding API retry aborted");
22422
+ await new Promise((resolve6, reject) => {
22423
+ const timer = setTimeout(done, waitMs);
22424
+ const onAbort = () => {
22425
+ clearTimeout(timer);
22426
+ abortSignal.removeEventListener("abort", onAbort);
22427
+ reject(new Error("Embedding API retry aborted"));
22428
+ };
22429
+ function done() {
22430
+ abortSignal.removeEventListener("abort", onAbort);
22431
+ resolve6();
22432
+ }
22433
+ abortSignal.addEventListener("abort", onAbort, { once: true });
22434
+ });
22371
22435
  }
22372
- var cache3, MAX_CACHE_SIZE3, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, APIEmbeddingProvider;
22436
+ var cache3, MAX_CACHE_SIZE3, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, EmbeddingAPIError, APIEmbeddingProvider;
22373
22437
  var init_api_provider = __esm({
22374
22438
  "src/embedding/api-provider.ts"() {
22375
22439
  "use strict";
@@ -22388,6 +22452,14 @@ var init_api_provider = __esm({
22388
22452
  DASHSCOPE_MAX_BATCH_SIZE = 10;
22389
22453
  MAX_RETRIES2 = 3;
22390
22454
  BASE_DELAY_MS = 500;
22455
+ EmbeddingAPIError = class extends Error {
22456
+ status;
22457
+ constructor(status, detail) {
22458
+ super(`Embedding API error (${status}): ${detail}`);
22459
+ this.name = "EmbeddingAPIError";
22460
+ this.status = status;
22461
+ }
22462
+ };
22391
22463
  APIEmbeddingProvider = class _APIEmbeddingProvider {
22392
22464
  name;
22393
22465
  dimensions;
@@ -22599,15 +22671,14 @@ var init_api_provider = __esm({
22599
22671
  }
22600
22672
  } catch (error40) {
22601
22673
  const providerLimit = parseBatchLimit(error40);
22602
- const fallbackSize = providerLimit ?? Math.ceil(chunkTexts.length / 2);
22603
- if (chunkTexts.length > 1 && fallbackSize < chunkTexts.length) {
22674
+ if (providerLimit !== null && chunkTexts.length > 1 && providerLimit < chunkTexts.length) {
22604
22675
  console.error(
22605
- `[memorix] Embedding batch too large for provider, retrying in chunks of ${fallbackSize}`
22676
+ `[memorix] Embedding batch too large for provider, retrying in chunks of ${providerLimit}`
22606
22677
  );
22607
- for (let start = 0; start < chunkTexts.length; start += fallbackSize) {
22678
+ for (let start = 0; start < chunkTexts.length; start += providerLimit) {
22608
22679
  await processChunk(
22609
- chunkTexts.slice(start, start + fallbackSize),
22610
- chunkIndices.slice(start, start + fallbackSize)
22680
+ chunkTexts.slice(start, start + providerLimit),
22681
+ chunkIndices.slice(start, start + providerLimit)
22611
22682
  );
22612
22683
  }
22613
22684
  return;
@@ -23471,22 +23542,23 @@ function getLLMConfig() {
23471
23542
  function setLLMConfig(config2) {
23472
23543
  currentConfig = config2;
23473
23544
  }
23474
- async function callLLM(systemPrompt, userMessage) {
23545
+ async function callLLM(systemPrompt, userMessage, signal) {
23475
23546
  if (!currentConfig) {
23476
23547
  throw new Error("LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.");
23477
23548
  }
23478
23549
  if (currentConfig.provider === "anthropic") {
23479
- return callAnthropic(systemPrompt, userMessage);
23550
+ return callAnthropic(systemPrompt, userMessage, signal);
23480
23551
  }
23481
- return callOpenAICompatible(systemPrompt, userMessage);
23552
+ return callOpenAICompatible(systemPrompt, userMessage, signal);
23482
23553
  }
23483
- async function callOpenAICompatible(systemPrompt, userMessage) {
23554
+ async function callOpenAICompatible(systemPrompt, userMessage, signal) {
23484
23555
  const config2 = currentConfig;
23485
23556
  let base = config2.baseUrl.replace(/\/+$/, "");
23486
23557
  if (!base.endsWith("/v1")) base += "/v1";
23487
23558
  const url2 = `${base}/chat/completions`;
23559
+ const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
23488
23560
  const response = await fetch(url2, {
23489
- signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS),
23561
+ signal: fetchSignal,
23490
23562
  method: "POST",
23491
23563
  headers: {
23492
23564
  "Content-Type": "application/json",
@@ -23503,10 +23575,10 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
23503
23575
  })
23504
23576
  });
23505
23577
  if (!response.ok) {
23506
- const error40 = await readResponseText(response, void 0, 64 * 1024).catch(() => "unknown error");
23578
+ const error40 = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
23507
23579
  throw new Error(`LLM API error (${response.status}): ${error40}`);
23508
23580
  }
23509
- const data = await readResponseJson(response);
23581
+ const data = await readResponseJson(response, signal);
23510
23582
  return {
23511
23583
  content: data.choices[0]?.message?.content ?? "",
23512
23584
  usage: data.usage ? {
@@ -23515,11 +23587,12 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
23515
23587
  } : void 0
23516
23588
  };
23517
23589
  }
23518
- async function callAnthropic(systemPrompt, userMessage) {
23590
+ async function callAnthropic(systemPrompt, userMessage, signal) {
23519
23591
  const config2 = currentConfig;
23520
23592
  const url2 = `${config2.baseUrl}/messages`;
23593
+ const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
23521
23594
  const response = await fetch(url2, {
23522
- signal: AbortSignal.timeout(LLM_CALL_TIMEOUT_MS),
23595
+ signal: fetchSignal,
23523
23596
  method: "POST",
23524
23597
  headers: {
23525
23598
  "Content-Type": "application/json",
@@ -23537,10 +23610,10 @@ async function callAnthropic(systemPrompt, userMessage) {
23537
23610
  })
23538
23611
  });
23539
23612
  if (!response.ok) {
23540
- const error40 = await readResponseText(response, void 0, 64 * 1024).catch(() => "unknown error");
23613
+ const error40 = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
23541
23614
  throw new Error(`Anthropic API error (${response.status}): ${error40}`);
23542
23615
  }
23543
- const data = await readResponseJson(response);
23616
+ const data = await readResponseJson(response, signal);
23544
23617
  return {
23545
23618
  content: data.content[0]?.text ?? "",
23546
23619
  usage: data.usage ? {
@@ -24045,6 +24118,57 @@ function withTimeout(promise2, ms2, label) {
24045
24118
  );
24046
24119
  });
24047
24120
  }
24121
+ function withTimeoutSignal(operation, ms2, label, parentSignal) {
24122
+ const controller = new AbortController();
24123
+ const signal = parentSignal ? AbortSignal.any([parentSignal, controller.signal]) : controller.signal;
24124
+ return new Promise((resolve6, reject) => {
24125
+ let settled = false;
24126
+ let timedOut = false;
24127
+ let timer;
24128
+ const cleanup = () => {
24129
+ if (timer !== void 0) clearTimeout(timer);
24130
+ parentSignal?.removeEventListener("abort", onParentAbort);
24131
+ };
24132
+ const onParentAbort = () => {
24133
+ if (settled || timedOut) return;
24134
+ settled = true;
24135
+ cleanup();
24136
+ reject(parentSignal?.reason ?? new Error(`${label} aborted`));
24137
+ };
24138
+ parentSignal?.addEventListener("abort", onParentAbort, { once: true });
24139
+ timer = setTimeout(() => {
24140
+ if (settled) return;
24141
+ timedOut = true;
24142
+ controller.abort(new Error(`${label} timed out after ${ms2}ms`));
24143
+ settled = true;
24144
+ cleanup();
24145
+ reject(new Error(`${label} timed out after ${ms2}ms`));
24146
+ }, ms2);
24147
+ let pending;
24148
+ try {
24149
+ pending = operation(signal);
24150
+ } catch (error40) {
24151
+ settled = true;
24152
+ cleanup();
24153
+ reject(error40);
24154
+ return;
24155
+ }
24156
+ pending.then(
24157
+ (value) => {
24158
+ if (settled) return;
24159
+ settled = true;
24160
+ cleanup();
24161
+ resolve6(value);
24162
+ },
24163
+ (error40) => {
24164
+ if (settled) return;
24165
+ settled = true;
24166
+ cleanup();
24167
+ reject(timedOut ? new Error(`${label} timed out after ${ms2}ms`) : error40);
24168
+ }
24169
+ );
24170
+ });
24171
+ }
24048
24172
  var init_timeout = __esm({
24049
24173
  "src/timeout.ts"() {
24050
24174
  "use strict";
@@ -178220,7 +178344,13 @@ async function maintainLongTermMemories(input) {
178220
178344
  }
178221
178345
  for (const group of groups.values()) {
178222
178346
  if (group.length < 2) continue;
178223
- group.sort((a4, b4) => Date.parse(b4.createdAt) - Date.parse(a4.createdAt));
178347
+ group.sort((a4, b4) => {
178348
+ const byCreatedAt = Date.parse(b4.createdAt) - Date.parse(a4.createdAt);
178349
+ if (byCreatedAt !== 0) return byCreatedAt;
178350
+ const byUpdatedAt = Date.parse(b4.updatedAt) - Date.parse(a4.updatedAt);
178351
+ if (byUpdatedAt !== 0) return byUpdatedAt;
178352
+ return b4.id.localeCompare(a4.id);
178353
+ });
178224
178354
  const newest = group[0];
178225
178355
  for (const older of group.slice(1)) {
178226
178356
  try {
@@ -184736,16 +184866,18 @@ async function searchObservations(options) {
184736
184866
  );
184737
184867
  } else {
184738
184868
  const EMBEDDING_TIMEOUT_MS = 15e3;
184739
- queryVector = await withTimeout(
184740
- provider2.embedInput ? provider2.embedInput(
184869
+ queryVector = await withTimeoutSignal(
184870
+ (signal) => provider2.embedInput ? provider2.embedInput(
184741
184871
  { modality: "text", text: expandedEmbeddingQuery },
184742
- { intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false }
184872
+ { intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false, signal }
184743
184873
  ) : provider2.embed(expandedEmbeddingQuery, {
184744
184874
  timeoutMs: EMBEDDING_TIMEOUT_MS,
184745
- retry: false
184875
+ retry: false,
184876
+ signal
184746
184877
  }),
184747
184878
  EMBEDDING_TIMEOUT_MS,
184748
- "Embedding"
184879
+ "Embedding",
184880
+ options.signal
184749
184881
  );
184750
184882
  mark("embedding");
184751
184883
  const cjkRatio = (originalQuery.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length / originalQuery.length;
@@ -199205,13 +199337,13 @@ function verifyType(declaredType, narrative, title) {
199205
199337
  }
199206
199338
  return { type: declaredType, corrected: false };
199207
199339
  }
199208
- async function extractFactsWithLLM(narrative, title, existingFacts) {
199340
+ async function extractFactsWithLLM(narrative, title, existingFacts, signal) {
199209
199341
  try {
199210
199342
  const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
199211
199343
  const input = `Title: ${title}
199212
199344
  Content: ${narrative}${existingFacts.length > 0 ? `
199213
199345
  Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
199214
- const response = await callLLM2(LLM_EXTRACT_PROMPT, input);
199346
+ const response = await callLLM2(LLM_EXTRACT_PROMPT, input, signal);
199215
199347
  const text2 = response.content.trim();
199216
199348
  const jsonMatch = text2.match(/\{[\s\S]*\}/);
199217
199349
  if (!jsonMatch) return [];
@@ -199220,15 +199352,16 @@ Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
199220
199352
  if (!Array.isArray(facts)) return [];
199221
199353
  const existingLower = new Set(existingFacts.map((f7) => f7.toLowerCase().trim()));
199222
199354
  return facts.filter((f7) => typeof f7 === "string" && f7.length >= 5).filter((f7) => !existingLower.has(f7.toLowerCase().trim())).slice(0, 10);
199223
- } catch {
199355
+ } catch (error40) {
199356
+ if (signal?.aborted) throw error40;
199224
199357
  return [];
199225
199358
  }
199226
199359
  }
199227
- async function runExtract(input, existingEntities, useLLM = false) {
199360
+ async function runExtract(input, existingEntities, useLLM = false, signal) {
199228
199361
  const callerFacts = input.facts ?? [];
199229
199362
  let extractedFacts;
199230
199363
  if (useLLM) {
199231
- extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts);
199364
+ extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts, signal);
199232
199365
  if (extractedFacts.length === 0) {
199233
199366
  extractedFacts = extractFacts2(input.narrative, callerFacts);
199234
199367
  }
@@ -199448,7 +199581,7 @@ function mergeFacts2(oldFacts, newFacts) {
199448
199581
  }
199449
199582
  return merged;
199450
199583
  }
199451
- async function resolveWithLLM(extracted, hits, getObservation2) {
199584
+ async function resolveWithLLM(extracted, hits, getObservation2, signal) {
199452
199585
  try {
199453
199586
  const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
199454
199587
  const existingMemories = hits.slice(0, 5).map((h5, i4) => ({
@@ -199465,7 +199598,7 @@ Facts: ${extracted.facts.join("; ")}
199465
199598
 
199466
199599
  EXISTING MEMORIES:
199467
199600
  ${existingMemories.map((m6) => `[ID:${m6.id}] ${m6.title} | ${m6.content} | Facts: ${m6.facts}`).join("\n")}`;
199468
- const response = await callLLM2(LLM_RESOLVE_PROMPT, input);
199601
+ const response = await callLLM2(LLM_RESOLVE_PROMPT, input, signal);
199469
199602
  const text2 = response.content.trim();
199470
199603
  const jsonMatch = text2.match(/\{[\s\S]*\}/);
199471
199604
  if (!jsonMatch) return null;
@@ -199502,7 +199635,8 @@ ${existingMemories.map((m6) => `[ID:${m6.id}] ${m6.title} | ${m6.content} | Fact
199502
199635
  };
199503
199636
  }
199504
199637
  return null;
199505
- } catch {
199638
+ } catch (error40) {
199639
+ if (signal?.aborted) throw error40;
199506
199640
  return null;
199507
199641
  }
199508
199642
  }
@@ -199520,19 +199654,20 @@ function scoreCandidate(extracted, candidate2) {
199520
199654
  const contradiction = hasContradiction(candidate2.narrative, extracted.narrative);
199521
199655
  return { score, searchSimilarity, entityMatch, richer, contradiction };
199522
199656
  }
199523
- async function runResolve(extracted, projectId, searchMemories3, getObservation2, useLLM = false) {
199657
+ async function runResolve(extracted, projectId, searchMemories3, getObservation2, useLLM = false, signal) {
199524
199658
  const query = `${extracted.title} ${extracted.narrative.substring(0, 200)}`;
199525
199659
  let hits;
199526
199660
  try {
199527
- hits = await searchMemories3(query, 5, projectId);
199528
- } catch {
199661
+ hits = await searchMemories3(query, 5, projectId, signal);
199662
+ } catch (error40) {
199663
+ if (signal?.aborted) throw error40;
199529
199664
  return { action: "new", reason: "Search unavailable, defaulting to new" };
199530
199665
  }
199531
199666
  if (hits.length === 0) {
199532
199667
  return { action: "new", reason: "No similar existing memories found" };
199533
199668
  }
199534
199669
  if (useLLM) {
199535
- const llmResult = await resolveWithLLM(extracted, hits, getObservation2);
199670
+ const llmResult = await resolveWithLLM(extracted, hits, getObservation2, signal);
199536
199671
  if (llmResult) return llmResult;
199537
199672
  }
199538
199673
  const scored = hits.map((hit) => ({
@@ -199954,7 +200089,7 @@ async function runFormation(input, config2) {
199954
200089
  const existingEntities = config2.getEntityNames();
199955
200090
  const extractStartTime = Date.now();
199956
200091
  emitStageEvent("extract", "start");
199957
- const extraction = await runExtract(input, existingEntities, config2.useLLM);
200092
+ const extraction = await runExtract(input, existingEntities, config2.useLLM, config2.signal);
199958
200093
  stageDurationsMs.extract = Date.now() - extractStartTime;
199959
200094
  emitStageEvent("extract", "success", stageDurationsMs.extract);
199960
200095
  stagesCompleted = 1;
@@ -199974,7 +200109,8 @@ async function runFormation(input, config2) {
199974
200109
  input.projectId,
199975
200110
  config2.searchMemories,
199976
200111
  config2.getObservation,
199977
- config2.useLLM
200112
+ config2.useLLM,
200113
+ config2.signal
199978
200114
  );
199979
200115
  stageDurationsMs.resolve = Date.now() - resolveStartTime;
199980
200116
  emitStageEvent("resolve", "success", stageDurationsMs.resolve);
@@ -258708,7 +258844,7 @@ The path should point to a directory containing a .git folder.`
258708
258844
  };
258709
258845
  const server = existingServer ?? new McpServer({
258710
258846
  name: "memorix",
258711
- version: true ? "1.5.0" : "1.0.1"
258847
+ version: true ? "1.5.1" : "1.0.1"
258712
258848
  });
258713
258849
  const originalRegisterTool = server.registerTool.bind(server);
258714
258850
  server.registerTool = ((name, ...args) => {
@@ -258897,8 +259033,8 @@ The path should point to a directory containing a .git folder.`
258897
259033
  mode: "active",
258898
259034
  useLLM: isLLMEnabled(),
258899
259035
  minValueScore: 0.3,
258900
- searchMemories: async (q4, limit2, pid) => {
258901
- const result = await compactSearch({ query: q4, limit: limit2, projectId: pid, status: "active", reader });
259036
+ searchMemories: async (q4, limit2, pid, signal) => {
259037
+ const result = await compactSearch({ query: q4, limit: limit2, projectId: pid, status: "active", reader, signal });
258902
259038
  if (result.entries.length === 0) return [];
258903
259039
  const details = await compactDetail(result.entries.map((e5) => e5.id), { reader });
258904
259040
  return details.documents.map((d4, i4) => ({
@@ -258928,16 +259064,19 @@ The path should point to a directory containing a .git folder.`
258928
259064
  getEntityNames: () => graphManager.getEntityNames(),
258929
259065
  onStageEvent: onFormationStageEvent
258930
259066
  };
258931
- formationResult = await withTimeout(
258932
- runFormation({
258933
- entityName,
258934
- type,
258935
- title,
258936
- narrative,
258937
- facts: safeFacts,
258938
- projectId: project.id,
258939
- source: "explicit"
258940
- }, formationConfig),
259067
+ formationResult = await withTimeoutSignal(
259068
+ async (signal) => {
259069
+ formationConfig.signal = signal;
259070
+ return runFormation({
259071
+ entityName,
259072
+ type,
259073
+ title,
259074
+ narrative,
259075
+ facts: safeFacts,
259076
+ projectId: project.id,
259077
+ source: "explicit"
259078
+ }, formationConfig);
259079
+ },
258941
259080
  FORMATION_TIMEOUT_MS,
258942
259081
  "Formation pipeline"
258943
259082
  );
@@ -259287,8 +259426,8 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
259287
259426
  mode: formationMode,
259288
259427
  useLLM: isLLMEnabled(),
259289
259428
  minValueScore: 0.3,
259290
- searchMemories: async (q4, limit2, pid) => {
259291
- const result = await compactSearch({ query: q4, limit: limit2, projectId: pid, status: "active", reader });
259429
+ searchMemories: async (q4, limit2, pid, signal) => {
259430
+ const result = await compactSearch({ query: q4, limit: limit2, projectId: pid, status: "active", reader, signal });
259292
259431
  if (result.entries.length === 0) return [];
259293
259432
  const details = await compactDetail(result.entries.map((e5) => e5.id), { reader });
259294
259433
  return details.documents.map((d4, i4) => ({
@@ -259309,8 +259448,11 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
259309
259448
  },
259310
259449
  getEntityNames: () => graphManager.getEntityNames()
259311
259450
  };
259312
- const formed = await withTimeout(
259313
- runFormation({ entityName, type, title, narrative, facts: safeFacts, projectId: project.id, source: "explicit", topicKey }, formationConfig),
259451
+ const formed = await withTimeoutSignal(
259452
+ async (signal) => {
259453
+ formationConfig.signal = signal;
259454
+ return runFormation({ entityName, type, title, narrative, facts: safeFacts, projectId: project.id, source: "explicit", topicKey }, formationConfig);
259455
+ },
259314
259456
  FORMATION_TIMEOUT_MS,
259315
259457
  "Shadow formation"
259316
259458
  );
File without changes