memorix 1.6.0 → 1.6.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 (119) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/TEAM.md +86 -86
  3. package/dist/cli/index.js +317 -62
  4. package/dist/cli/memcode.js +12 -1
  5. package/dist/index.js +56 -9
  6. package/dist/maintenance-runner.js +54 -7
  7. package/dist/media-audio-runner.js +54 -7
  8. package/dist/media-video-runner.js +54 -7
  9. package/dist/memcode-runtime/CHANGELOG.md +24 -0
  10. package/dist/sdk.js +55 -8
  11. package/dist/vector-backfill-runner.js +54 -7
  12. package/docs/AGENT_OPERATOR_PLAYBOOK.md +11 -3
  13. package/docs/API_REFERENCE.md +1 -1
  14. package/docs/DESIGN_DECISIONS.md +357 -357
  15. package/docs/DOCKER.md +5 -1
  16. package/docs/PERFORMANCE.md +2 -2
  17. package/docs/README.md +3 -1
  18. package/docs/SETUP.md +8 -2
  19. package/package.json +1 -1
  20. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  21. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  22. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  23. package/plugins/copilot/memorix/plugin.json +1 -1
  24. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  25. package/plugins/omp/memorix/package.json +1 -1
  26. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  27. package/plugins/pi/memorix/package.json +1 -1
  28. package/server.json +2 -2
  29. package/src/audit/index.ts +156 -156
  30. package/src/cli/commands/agent-integrations.ts +9 -3
  31. package/src/cli/commands/doctor.ts +46 -15
  32. package/src/cli/commands/formation.ts +48 -48
  33. package/src/cli/commands/git-hook-install.ts +111 -111
  34. package/src/cli/commands/handoff.ts +54 -54
  35. package/src/cli/commands/hook.ts +13 -1
  36. package/src/cli/commands/hooks-status.ts +63 -63
  37. package/src/cli/commands/ingest.ts +44 -44
  38. package/src/cli/commands/integrate-shared.ts +15 -15
  39. package/src/cli/commands/lock.ts +82 -82
  40. package/src/cli/commands/message.ts +104 -104
  41. package/src/cli/commands/poll.ts +58 -58
  42. package/src/cli/commands/reasoning.ts +118 -118
  43. package/src/cli/commands/serve-http.ts +68 -7
  44. package/src/cli/commands/skills.ts +114 -114
  45. package/src/cli/commands/task.ts +167 -167
  46. package/src/cli/commands/transfer.ts +47 -47
  47. package/src/cli/heap.ts +76 -0
  48. package/src/cli/index.ts +406 -406
  49. package/src/cli/invocation.ts +7 -4
  50. package/src/cli/tui/ChatView.tsx +234 -234
  51. package/src/cli/tui/CommandBar.tsx +312 -312
  52. package/src/cli/tui/ContextRail.tsx +118 -118
  53. package/src/cli/tui/HeaderBar.tsx +72 -72
  54. package/src/cli/tui/LogoBanner.tsx +51 -51
  55. package/src/cli/tui/index.ts +41 -41
  56. package/src/cli/version.ts +7 -7
  57. package/src/cli/workbench.ts +1 -1
  58. package/src/dashboard/project-classification.ts +64 -64
  59. package/src/embedding/provider.ts +76 -6
  60. package/src/git/hooks-path.ts +85 -85
  61. package/src/hooks/handler.ts +9 -18
  62. package/src/hooks/lifecycle.ts +173 -0
  63. package/src/hooks/pattern-detector.ts +173 -173
  64. package/src/hooks/significance-filter.ts +250 -250
  65. package/src/llm/memory-manager.ts +328 -328
  66. package/src/llm/quality.ts +248 -248
  67. package/src/memory/attribution-guard.ts +249 -249
  68. package/src/memory/disclosure-policy.ts +135 -135
  69. package/src/memory/entity-extractor.ts +197 -197
  70. package/src/memory/formation/evaluate.ts +217 -217
  71. package/src/memory/freshness.ts +122 -122
  72. package/src/memory/graph.ts +197 -197
  73. package/src/memory/refs.ts +94 -94
  74. package/src/memory/secret-filter.ts +79 -79
  75. package/src/orchestrate/adapters/claude-stream.ts +192 -192
  76. package/src/orchestrate/adapters/claude.ts +111 -111
  77. package/src/orchestrate/adapters/codex-stream.ts +134 -134
  78. package/src/orchestrate/adapters/codex.ts +41 -41
  79. package/src/orchestrate/adapters/gemini-stream.ts +166 -166
  80. package/src/orchestrate/adapters/gemini.ts +42 -42
  81. package/src/orchestrate/adapters/index.ts +73 -73
  82. package/src/orchestrate/adapters/opencode-stream.ts +143 -143
  83. package/src/orchestrate/adapters/opencode.ts +47 -47
  84. package/src/orchestrate/adapters/types.ts +77 -77
  85. package/src/orchestrate/capability-router.ts +284 -284
  86. package/src/orchestrate/cost-tracker.ts +219 -219
  87. package/src/orchestrate/error-recovery.ts +191 -191
  88. package/src/orchestrate/evidence.ts +140 -140
  89. package/src/orchestrate/ledger.ts +110 -110
  90. package/src/orchestrate/memorix-bridge.ts +343 -343
  91. package/src/orchestrate/output-budget.ts +80 -80
  92. package/src/orchestrate/permission.ts +152 -152
  93. package/src/orchestrate/pipeline-trace.ts +131 -131
  94. package/src/orchestrate/prompt-builder.ts +155 -155
  95. package/src/orchestrate/ring-buffer.ts +37 -37
  96. package/src/orchestrate/task-graph.ts +389 -389
  97. package/src/project/aliases.ts +374 -374
  98. package/src/rules/adapters/trae.ts +56 -56
  99. package/src/rules/syncer.ts +235 -235
  100. package/src/search/query-expansion.ts +52 -52
  101. package/src/server/formation-timeout.ts +27 -27
  102. package/src/skills/mini-skills.ts +386 -386
  103. package/src/store/chat-store.ts +119 -119
  104. package/src/store/graph-store.ts +249 -249
  105. package/src/store/mini-skill-store.ts +349 -349
  106. package/src/store/persistence-json.ts +212 -212
  107. package/src/store/persistence.ts +291 -291
  108. package/src/store/project-affinity.ts +195 -195
  109. package/src/team/event-bus.ts +76 -76
  110. package/src/team/handoff.ts +161 -161
  111. package/src/team/poll.ts +132 -132
  112. package/src/workspace/mcp-adapters/codex.ts +191 -191
  113. package/src/workspace/mcp-adapters/copilot.ts +105 -105
  114. package/src/workspace/mcp-adapters/cursor.ts +53 -53
  115. package/src/workspace/mcp-adapters/kiro.ts +64 -64
  116. package/src/workspace/mcp-adapters/opencode.ts +123 -123
  117. package/src/workspace/mcp-adapters/trae.ts +134 -134
  118. package/src/workspace/mcp-adapters/windsurf.ts +91 -91
  119. package/src/workspace/sanitizer.ts +60 -60
@@ -2,7 +2,18 @@
2
2
  import {spawnSync as __ms} from "node:child_process";
3
3
  import {fileURLToPath as __fu} from "node:url";
4
4
  if(!process.env.__MEMORIX_HEAP){process.env.__MEMORIX_HEAP="1";
5
- let r=__ms(process.execPath,["--max-old-space-size=4096",__fu(import.meta.url),...process.argv.slice(2)],{stdio:"inherit",env:process.env,windowsHide:true});
5
+ const __args=process.argv.slice(2);
6
+ let __cmd;
7
+ for(let __i=0;__i<__args.length;__i++){
8
+ const __a=__args[__i];
9
+ if(__a==="--")break;
10
+ if(__a.startsWith("-")){if(!__a.includes("=")&&__args[__i+1]&&!__args[__i+1].startsWith("-"))__i++;continue;}
11
+ __cmd=__a;break;}
12
+ const __fallback=__cmd==="hook"?512:4096;
13
+ const __raw=__cmd==="hook"?process.env.MEMORIX_HOOK_HEAP_MB:process.env.MEMORIX_HEAP_MB;
14
+ const __n=Number(__raw);
15
+ const __heap=(Number.isFinite(__n)&&__n>=64&&__n<=16384)?String(Math.floor(__n)):String(__fallback);
16
+ let r=__ms(process.execPath,["--max-old-space-size="+__heap,__fu(import.meta.url),...process.argv.slice(2)],{stdio:"inherit",env:process.env,windowsHide:true});
6
17
  process.exit(r.status??1);}
7
18
  import {createRequire as __memorix_cjsRequire} from "module";
8
19
  const require = __memorix_cjsRequire(import.meta.url);
package/dist/index.js CHANGED
@@ -4438,6 +4438,7 @@ __export(provider_exports, {
4438
4438
  MAX_INLINE_EMBEDDING_BYTES: () => MAX_INLINE_EMBEDDING_BYTES,
4439
4439
  UnsupportedEmbeddingModalityError: () => UnsupportedEmbeddingModalityError,
4440
4440
  getEmbeddingProvider: () => getEmbeddingProvider,
4441
+ getEmbeddingRuntimeHealth: () => getEmbeddingRuntimeHealth,
4441
4442
  isEmbeddingExplicitlyDisabled: () => isEmbeddingExplicitlyDisabled,
4442
4443
  isVectorSearchAvailable: () => isVectorSearchAvailable,
4443
4444
  resetProvider: () => resetProvider,
@@ -4545,13 +4546,36 @@ function isTemporaryEmbeddingFailure(error) {
4545
4546
  if (!(error instanceof Error)) return false;
4546
4547
  return /embedding api error \(401\)/i.test(error.message) || /invalid_api_key/i.test(error.message) || /incorrect api key/i.test(error.message) || /unauthorized/i.test(error.message) || /embedding api timeout/i.test(error.message) || /embedding api error \((402|429|5\d\d)\)/i.test(error.message) || /quota exceeded/i.test(error.message) || /account balance/i.test(error.message) || /fetch failed/i.test(error.message) || /econnreset/i.test(error.message) || /econnrefused/i.test(error.message) || /temporarily unavailable/i.test(error.message);
4547
4548
  }
4549
+ function classifyEmbeddingFailure(error) {
4550
+ const message = error instanceof Error ? error.message : String(error);
4551
+ if (/embedding api error \(401\)|invalid_api_key|incorrect api key|unauthorized/i.test(message)) {
4552
+ return "authorization";
4553
+ }
4554
+ if (/embedding api error \(402\)|quota exceeded|account balance/i.test(message)) {
4555
+ return "billing";
4556
+ }
4557
+ if (/embedding api timeout|abort/i.test(message)) {
4558
+ return "timeout";
4559
+ }
4560
+ return "upstream";
4561
+ }
4548
4562
  function markTemporaryFailure(reason) {
4549
4563
  provider = null;
4550
4564
  initPromise = null;
4551
4565
  lastInitWasTemporaryFailure = true;
4552
4566
  lastFailureTimestamp = Date.now();
4567
+ lastEmbeddingFailure = {
4568
+ kind: classifyEmbeddingFailure(reason),
4569
+ occurredAt: lastFailureTimestamp
4570
+ };
4553
4571
  const message = reason instanceof Error ? reason.message : String(reason);
4554
- warnOnce(`[memorix] Embedding provider temporarily unavailable at runtime: ${message}`);
4572
+ warnOnce(`[memorix] Embedding provider unavailable at runtime: ${message}`);
4573
+ }
4574
+ function markProviderReady(candidate) {
4575
+ provider = wrapProvider(candidate);
4576
+ lastInitWasTemporaryFailure = false;
4577
+ lastEmbeddingFailure = null;
4578
+ return provider;
4555
4579
  }
4556
4580
  async function createFastEmbedProvider() {
4557
4581
  try {
@@ -4667,35 +4691,35 @@ async function getEmbeddingProvider(options = {}) {
4667
4691
  if (mode === "fastembed") {
4668
4692
  const initialized = await createFastEmbedProvider();
4669
4693
  if (!initialized) return null;
4670
- provider = wrapProvider(initialized);
4694
+ provider = markProviderReady(initialized);
4671
4695
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4672
4696
  return provider;
4673
4697
  }
4674
4698
  if (mode === "transformers") {
4675
4699
  const initialized = await createTransformersProvider();
4676
4700
  if (!initialized) return null;
4677
- provider = wrapProvider(initialized);
4701
+ provider = markProviderReady(initialized);
4678
4702
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4679
4703
  return provider;
4680
4704
  }
4681
4705
  if (mode === "api") {
4682
4706
  const initialized = await createAPIProvider(options);
4683
4707
  if (!initialized) return null;
4684
- provider = wrapProvider(initialized);
4708
+ provider = markProviderReady(initialized);
4685
4709
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4686
4710
  return provider;
4687
4711
  }
4688
4712
  if (hasAPIEmbeddingConfig()) {
4689
4713
  const initialized = await createAPIProvider(options);
4690
4714
  if (initialized) {
4691
- provider = wrapProvider(initialized);
4715
+ provider = markProviderReady(initialized);
4692
4716
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4693
4717
  return provider;
4694
4718
  }
4695
4719
  }
4696
4720
  const localFallback = await createLocalFallbackProvider();
4697
4721
  if (localFallback) {
4698
- provider = wrapProvider(localFallback);
4722
+ provider = markProviderReady(localFallback);
4699
4723
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4700
4724
  return provider;
4701
4725
  }
@@ -4717,6 +4741,27 @@ async function isVectorSearchAvailable() {
4717
4741
  const p = await getEmbeddingProvider();
4718
4742
  return p !== null;
4719
4743
  }
4744
+ function getEmbeddingRuntimeHealth() {
4745
+ const mode = getEmbeddingMode2();
4746
+ if (mode === "off") return { status: "disabled" };
4747
+ if (lastInitWasTemporaryFailure && lastEmbeddingFailure) {
4748
+ return {
4749
+ status: "degraded",
4750
+ failure: {
4751
+ kind: lastEmbeddingFailure.kind,
4752
+ occurredAt: new Date(lastEmbeddingFailure.occurredAt).toISOString(),
4753
+ retryAfterMs: Math.max(0, RETRY_COOLDOWN_MS - (Date.now() - lastEmbeddingFailure.occurredAt))
4754
+ }
4755
+ };
4756
+ }
4757
+ if (provider) {
4758
+ return {
4759
+ status: "ready",
4760
+ provider: { name: provider.name, dimensions: provider.dimensions }
4761
+ };
4762
+ }
4763
+ return { status: "uninitialized" };
4764
+ }
4720
4765
  function isEmbeddingExplicitlyDisabled() {
4721
4766
  return getEmbeddingMode2() === "off";
4722
4767
  }
@@ -4725,10 +4770,11 @@ function resetProvider() {
4725
4770
  initPromise = null;
4726
4771
  lastInitWasTemporaryFailure = false;
4727
4772
  lastFailureTimestamp = 0;
4773
+ lastEmbeddingFailure = null;
4728
4774
  lastEmbeddingWarning = "";
4729
4775
  lastEmbeddingWarningAt = 0;
4730
4776
  }
4731
- var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
4777
+ var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
4732
4778
  var init_provider = __esm({
4733
4779
  "src/embedding/provider.ts"() {
4734
4780
  "use strict";
@@ -4753,6 +4799,7 @@ var init_provider = __esm({
4753
4799
  provider = null;
4754
4800
  initPromise = null;
4755
4801
  lastInitWasTemporaryFailure = false;
4802
+ lastEmbeddingFailure = null;
4756
4803
  lastEmbeddingWarning = "";
4757
4804
  lastEmbeddingWarningAt = 0;
4758
4805
  WARNING_COOLDOWN_MS = 3e4;
@@ -166096,7 +166143,7 @@ The path should point to a directory containing a .git folder.`
166096
166143
  };
166097
166144
  const server = existingServer ?? new McpServer({
166098
166145
  name: "memorix",
166099
- version: true ? "1.6.0" : "1.0.1"
166146
+ version: true ? "1.6.1" : "1.0.1"
166100
166147
  });
166101
166148
  const originalRegisterTool = server.registerTool.bind(server);
166102
166149
  server.registerTool = ((name, ...args) => {
@@ -170502,7 +170549,7 @@ var init_serve_shared = __esm({
170502
170549
 
170503
170550
  // src/cli/version.ts
170504
170551
  function getCliVersion() {
170505
- return true ? "1.6.0" : pkg.version;
170552
+ return true ? "1.6.1" : pkg.version;
170506
170553
  }
170507
170554
  var init_version3 = __esm({
170508
170555
  "src/cli/version.ts"() {
@@ -4308,6 +4308,7 @@ __export(provider_exports2, {
4308
4308
  MAX_INLINE_EMBEDDING_BYTES: () => MAX_INLINE_EMBEDDING_BYTES,
4309
4309
  UnsupportedEmbeddingModalityError: () => UnsupportedEmbeddingModalityError,
4310
4310
  getEmbeddingProvider: () => getEmbeddingProvider,
4311
+ getEmbeddingRuntimeHealth: () => getEmbeddingRuntimeHealth,
4311
4312
  isEmbeddingExplicitlyDisabled: () => isEmbeddingExplicitlyDisabled,
4312
4313
  isVectorSearchAvailable: () => isVectorSearchAvailable,
4313
4314
  resetProvider: () => resetProvider,
@@ -4415,13 +4416,36 @@ function isTemporaryEmbeddingFailure(error) {
4415
4416
  if (!(error instanceof Error)) return false;
4416
4417
  return /embedding api error \(401\)/i.test(error.message) || /invalid_api_key/i.test(error.message) || /incorrect api key/i.test(error.message) || /unauthorized/i.test(error.message) || /embedding api timeout/i.test(error.message) || /embedding api error \((402|429|5\d\d)\)/i.test(error.message) || /quota exceeded/i.test(error.message) || /account balance/i.test(error.message) || /fetch failed/i.test(error.message) || /econnreset/i.test(error.message) || /econnrefused/i.test(error.message) || /temporarily unavailable/i.test(error.message);
4417
4418
  }
4419
+ function classifyEmbeddingFailure(error) {
4420
+ const message = error instanceof Error ? error.message : String(error);
4421
+ if (/embedding api error \(401\)|invalid_api_key|incorrect api key|unauthorized/i.test(message)) {
4422
+ return "authorization";
4423
+ }
4424
+ if (/embedding api error \(402\)|quota exceeded|account balance/i.test(message)) {
4425
+ return "billing";
4426
+ }
4427
+ if (/embedding api timeout|abort/i.test(message)) {
4428
+ return "timeout";
4429
+ }
4430
+ return "upstream";
4431
+ }
4418
4432
  function markTemporaryFailure(reason) {
4419
4433
  provider = null;
4420
4434
  initPromise = null;
4421
4435
  lastInitWasTemporaryFailure = true;
4422
4436
  lastFailureTimestamp = Date.now();
4437
+ lastEmbeddingFailure = {
4438
+ kind: classifyEmbeddingFailure(reason),
4439
+ occurredAt: lastFailureTimestamp
4440
+ };
4423
4441
  const message = reason instanceof Error ? reason.message : String(reason);
4424
- warnOnce(`[memorix] Embedding provider temporarily unavailable at runtime: ${message}`);
4442
+ warnOnce(`[memorix] Embedding provider unavailable at runtime: ${message}`);
4443
+ }
4444
+ function markProviderReady(candidate) {
4445
+ provider = wrapProvider(candidate);
4446
+ lastInitWasTemporaryFailure = false;
4447
+ lastEmbeddingFailure = null;
4448
+ return provider;
4425
4449
  }
4426
4450
  async function createFastEmbedProvider() {
4427
4451
  try {
@@ -4537,35 +4561,35 @@ async function getEmbeddingProvider(options = {}) {
4537
4561
  if (mode === "fastembed") {
4538
4562
  const initialized = await createFastEmbedProvider();
4539
4563
  if (!initialized) return null;
4540
- provider = wrapProvider(initialized);
4564
+ provider = markProviderReady(initialized);
4541
4565
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4542
4566
  return provider;
4543
4567
  }
4544
4568
  if (mode === "transformers") {
4545
4569
  const initialized = await createTransformersProvider();
4546
4570
  if (!initialized) return null;
4547
- provider = wrapProvider(initialized);
4571
+ provider = markProviderReady(initialized);
4548
4572
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4549
4573
  return provider;
4550
4574
  }
4551
4575
  if (mode === "api") {
4552
4576
  const initialized = await createAPIProvider(options);
4553
4577
  if (!initialized) return null;
4554
- provider = wrapProvider(initialized);
4578
+ provider = markProviderReady(initialized);
4555
4579
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4556
4580
  return provider;
4557
4581
  }
4558
4582
  if (hasAPIEmbeddingConfig()) {
4559
4583
  const initialized = await createAPIProvider(options);
4560
4584
  if (initialized) {
4561
- provider = wrapProvider(initialized);
4585
+ provider = markProviderReady(initialized);
4562
4586
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4563
4587
  return provider;
4564
4588
  }
4565
4589
  }
4566
4590
  const localFallback = await createLocalFallbackProvider();
4567
4591
  if (localFallback) {
4568
- provider = wrapProvider(localFallback);
4592
+ provider = markProviderReady(localFallback);
4569
4593
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4570
4594
  return provider;
4571
4595
  }
@@ -4587,6 +4611,27 @@ async function isVectorSearchAvailable() {
4587
4611
  const p = await getEmbeddingProvider();
4588
4612
  return p !== null;
4589
4613
  }
4614
+ function getEmbeddingRuntimeHealth() {
4615
+ const mode = getEmbeddingMode2();
4616
+ if (mode === "off") return { status: "disabled" };
4617
+ if (lastInitWasTemporaryFailure && lastEmbeddingFailure) {
4618
+ return {
4619
+ status: "degraded",
4620
+ failure: {
4621
+ kind: lastEmbeddingFailure.kind,
4622
+ occurredAt: new Date(lastEmbeddingFailure.occurredAt).toISOString(),
4623
+ retryAfterMs: Math.max(0, RETRY_COOLDOWN_MS - (Date.now() - lastEmbeddingFailure.occurredAt))
4624
+ }
4625
+ };
4626
+ }
4627
+ if (provider) {
4628
+ return {
4629
+ status: "ready",
4630
+ provider: { name: provider.name, dimensions: provider.dimensions }
4631
+ };
4632
+ }
4633
+ return { status: "uninitialized" };
4634
+ }
4590
4635
  function isEmbeddingExplicitlyDisabled() {
4591
4636
  return getEmbeddingMode2() === "off";
4592
4637
  }
@@ -4595,10 +4640,11 @@ function resetProvider() {
4595
4640
  initPromise = null;
4596
4641
  lastInitWasTemporaryFailure = false;
4597
4642
  lastFailureTimestamp = 0;
4643
+ lastEmbeddingFailure = null;
4598
4644
  lastEmbeddingWarning = "";
4599
4645
  lastEmbeddingWarningAt = 0;
4600
4646
  }
4601
- var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
4647
+ var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
4602
4648
  var init_provider2 = __esm({
4603
4649
  "src/embedding/provider.ts"() {
4604
4650
  "use strict";
@@ -4623,6 +4669,7 @@ var init_provider2 = __esm({
4623
4669
  provider = null;
4624
4670
  initPromise = null;
4625
4671
  lastInitWasTemporaryFailure = false;
4672
+ lastEmbeddingFailure = null;
4626
4673
  lastEmbeddingWarning = "";
4627
4674
  lastEmbeddingWarningAt = 0;
4628
4675
  WARNING_COOLDOWN_MS = 3e4;
@@ -4189,6 +4189,7 @@ __export(provider_exports, {
4189
4189
  MAX_INLINE_EMBEDDING_BYTES: () => MAX_INLINE_EMBEDDING_BYTES,
4190
4190
  UnsupportedEmbeddingModalityError: () => UnsupportedEmbeddingModalityError,
4191
4191
  getEmbeddingProvider: () => getEmbeddingProvider,
4192
+ getEmbeddingRuntimeHealth: () => getEmbeddingRuntimeHealth,
4192
4193
  isEmbeddingExplicitlyDisabled: () => isEmbeddingExplicitlyDisabled,
4193
4194
  isVectorSearchAvailable: () => isVectorSearchAvailable,
4194
4195
  resetProvider: () => resetProvider,
@@ -4296,13 +4297,36 @@ function isTemporaryEmbeddingFailure(error) {
4296
4297
  if (!(error instanceof Error)) return false;
4297
4298
  return /embedding api error \(401\)/i.test(error.message) || /invalid_api_key/i.test(error.message) || /incorrect api key/i.test(error.message) || /unauthorized/i.test(error.message) || /embedding api timeout/i.test(error.message) || /embedding api error \((402|429|5\d\d)\)/i.test(error.message) || /quota exceeded/i.test(error.message) || /account balance/i.test(error.message) || /fetch failed/i.test(error.message) || /econnreset/i.test(error.message) || /econnrefused/i.test(error.message) || /temporarily unavailable/i.test(error.message);
4298
4299
  }
4300
+ function classifyEmbeddingFailure(error) {
4301
+ const message = error instanceof Error ? error.message : String(error);
4302
+ if (/embedding api error \(401\)|invalid_api_key|incorrect api key|unauthorized/i.test(message)) {
4303
+ return "authorization";
4304
+ }
4305
+ if (/embedding api error \(402\)|quota exceeded|account balance/i.test(message)) {
4306
+ return "billing";
4307
+ }
4308
+ if (/embedding api timeout|abort/i.test(message)) {
4309
+ return "timeout";
4310
+ }
4311
+ return "upstream";
4312
+ }
4299
4313
  function markTemporaryFailure(reason) {
4300
4314
  provider = null;
4301
4315
  initPromise = null;
4302
4316
  lastInitWasTemporaryFailure = true;
4303
4317
  lastFailureTimestamp = Date.now();
4318
+ lastEmbeddingFailure = {
4319
+ kind: classifyEmbeddingFailure(reason),
4320
+ occurredAt: lastFailureTimestamp
4321
+ };
4304
4322
  const message = reason instanceof Error ? reason.message : String(reason);
4305
- warnOnce(`[memorix] Embedding provider temporarily unavailable at runtime: ${message}`);
4323
+ warnOnce(`[memorix] Embedding provider unavailable at runtime: ${message}`);
4324
+ }
4325
+ function markProviderReady(candidate) {
4326
+ provider = wrapProvider(candidate);
4327
+ lastInitWasTemporaryFailure = false;
4328
+ lastEmbeddingFailure = null;
4329
+ return provider;
4306
4330
  }
4307
4331
  async function createFastEmbedProvider() {
4308
4332
  try {
@@ -4418,35 +4442,35 @@ async function getEmbeddingProvider(options = {}) {
4418
4442
  if (mode === "fastembed") {
4419
4443
  const initialized = await createFastEmbedProvider();
4420
4444
  if (!initialized) return null;
4421
- provider = wrapProvider(initialized);
4445
+ provider = markProviderReady(initialized);
4422
4446
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4423
4447
  return provider;
4424
4448
  }
4425
4449
  if (mode === "transformers") {
4426
4450
  const initialized = await createTransformersProvider();
4427
4451
  if (!initialized) return null;
4428
- provider = wrapProvider(initialized);
4452
+ provider = markProviderReady(initialized);
4429
4453
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4430
4454
  return provider;
4431
4455
  }
4432
4456
  if (mode === "api") {
4433
4457
  const initialized = await createAPIProvider(options);
4434
4458
  if (!initialized) return null;
4435
- provider = wrapProvider(initialized);
4459
+ provider = markProviderReady(initialized);
4436
4460
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4437
4461
  return provider;
4438
4462
  }
4439
4463
  if (hasAPIEmbeddingConfig()) {
4440
4464
  const initialized = await createAPIProvider(options);
4441
4465
  if (initialized) {
4442
- provider = wrapProvider(initialized);
4466
+ provider = markProviderReady(initialized);
4443
4467
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4444
4468
  return provider;
4445
4469
  }
4446
4470
  }
4447
4471
  const localFallback = await createLocalFallbackProvider();
4448
4472
  if (localFallback) {
4449
- provider = wrapProvider(localFallback);
4473
+ provider = markProviderReady(localFallback);
4450
4474
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
4451
4475
  return provider;
4452
4476
  }
@@ -4468,6 +4492,27 @@ async function isVectorSearchAvailable() {
4468
4492
  const p = await getEmbeddingProvider();
4469
4493
  return p !== null;
4470
4494
  }
4495
+ function getEmbeddingRuntimeHealth() {
4496
+ const mode = getEmbeddingMode2();
4497
+ if (mode === "off") return { status: "disabled" };
4498
+ if (lastInitWasTemporaryFailure && lastEmbeddingFailure) {
4499
+ return {
4500
+ status: "degraded",
4501
+ failure: {
4502
+ kind: lastEmbeddingFailure.kind,
4503
+ occurredAt: new Date(lastEmbeddingFailure.occurredAt).toISOString(),
4504
+ retryAfterMs: Math.max(0, RETRY_COOLDOWN_MS - (Date.now() - lastEmbeddingFailure.occurredAt))
4505
+ }
4506
+ };
4507
+ }
4508
+ if (provider) {
4509
+ return {
4510
+ status: "ready",
4511
+ provider: { name: provider.name, dimensions: provider.dimensions }
4512
+ };
4513
+ }
4514
+ return { status: "uninitialized" };
4515
+ }
4471
4516
  function isEmbeddingExplicitlyDisabled() {
4472
4517
  return getEmbeddingMode2() === "off";
4473
4518
  }
@@ -4476,10 +4521,11 @@ function resetProvider() {
4476
4521
  initPromise = null;
4477
4522
  lastInitWasTemporaryFailure = false;
4478
4523
  lastFailureTimestamp = 0;
4524
+ lastEmbeddingFailure = null;
4479
4525
  lastEmbeddingWarning = "";
4480
4526
  lastEmbeddingWarningAt = 0;
4481
4527
  }
4482
- var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
4528
+ var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
4483
4529
  var init_provider = __esm({
4484
4530
  "src/embedding/provider.ts"() {
4485
4531
  "use strict";
@@ -4504,6 +4550,7 @@ var init_provider = __esm({
4504
4550
  provider = null;
4505
4551
  initPromise = null;
4506
4552
  lastInitWasTemporaryFailure = false;
4553
+ lastEmbeddingFailure = null;
4507
4554
  lastEmbeddingWarning = "";
4508
4555
  lastEmbeddingWarningAt = 0;
4509
4556
  WARNING_COOLDOWN_MS = 3e4;
@@ -3206,6 +3206,7 @@ __export(provider_exports, {
3206
3206
  MAX_INLINE_EMBEDDING_BYTES: () => MAX_INLINE_EMBEDDING_BYTES,
3207
3207
  UnsupportedEmbeddingModalityError: () => UnsupportedEmbeddingModalityError,
3208
3208
  getEmbeddingProvider: () => getEmbeddingProvider,
3209
+ getEmbeddingRuntimeHealth: () => getEmbeddingRuntimeHealth,
3209
3210
  isEmbeddingExplicitlyDisabled: () => isEmbeddingExplicitlyDisabled,
3210
3211
  isVectorSearchAvailable: () => isVectorSearchAvailable,
3211
3212
  resetProvider: () => resetProvider,
@@ -3313,13 +3314,36 @@ function isTemporaryEmbeddingFailure(error) {
3313
3314
  if (!(error instanceof Error)) return false;
3314
3315
  return /embedding api error \(401\)/i.test(error.message) || /invalid_api_key/i.test(error.message) || /incorrect api key/i.test(error.message) || /unauthorized/i.test(error.message) || /embedding api timeout/i.test(error.message) || /embedding api error \((402|429|5\d\d)\)/i.test(error.message) || /quota exceeded/i.test(error.message) || /account balance/i.test(error.message) || /fetch failed/i.test(error.message) || /econnreset/i.test(error.message) || /econnrefused/i.test(error.message) || /temporarily unavailable/i.test(error.message);
3315
3316
  }
3317
+ function classifyEmbeddingFailure(error) {
3318
+ const message = error instanceof Error ? error.message : String(error);
3319
+ if (/embedding api error \(401\)|invalid_api_key|incorrect api key|unauthorized/i.test(message)) {
3320
+ return "authorization";
3321
+ }
3322
+ if (/embedding api error \(402\)|quota exceeded|account balance/i.test(message)) {
3323
+ return "billing";
3324
+ }
3325
+ if (/embedding api timeout|abort/i.test(message)) {
3326
+ return "timeout";
3327
+ }
3328
+ return "upstream";
3329
+ }
3316
3330
  function markTemporaryFailure(reason) {
3317
3331
  provider = null;
3318
3332
  initPromise = null;
3319
3333
  lastInitWasTemporaryFailure = true;
3320
3334
  lastFailureTimestamp = Date.now();
3335
+ lastEmbeddingFailure = {
3336
+ kind: classifyEmbeddingFailure(reason),
3337
+ occurredAt: lastFailureTimestamp
3338
+ };
3321
3339
  const message = reason instanceof Error ? reason.message : String(reason);
3322
- warnOnce(`[memorix] Embedding provider temporarily unavailable at runtime: ${message}`);
3340
+ warnOnce(`[memorix] Embedding provider unavailable at runtime: ${message}`);
3341
+ }
3342
+ function markProviderReady(candidate) {
3343
+ provider = wrapProvider(candidate);
3344
+ lastInitWasTemporaryFailure = false;
3345
+ lastEmbeddingFailure = null;
3346
+ return provider;
3323
3347
  }
3324
3348
  async function createFastEmbedProvider() {
3325
3349
  try {
@@ -3435,35 +3459,35 @@ async function getEmbeddingProvider(options = {}) {
3435
3459
  if (mode === "fastembed") {
3436
3460
  const initialized = await createFastEmbedProvider();
3437
3461
  if (!initialized) return null;
3438
- provider = wrapProvider(initialized);
3462
+ provider = markProviderReady(initialized);
3439
3463
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
3440
3464
  return provider;
3441
3465
  }
3442
3466
  if (mode === "transformers") {
3443
3467
  const initialized = await createTransformersProvider();
3444
3468
  if (!initialized) return null;
3445
- provider = wrapProvider(initialized);
3469
+ provider = markProviderReady(initialized);
3446
3470
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
3447
3471
  return provider;
3448
3472
  }
3449
3473
  if (mode === "api") {
3450
3474
  const initialized = await createAPIProvider(options);
3451
3475
  if (!initialized) return null;
3452
- provider = wrapProvider(initialized);
3476
+ provider = markProviderReady(initialized);
3453
3477
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
3454
3478
  return provider;
3455
3479
  }
3456
3480
  if (hasAPIEmbeddingConfig()) {
3457
3481
  const initialized = await createAPIProvider(options);
3458
3482
  if (initialized) {
3459
- provider = wrapProvider(initialized);
3483
+ provider = markProviderReady(initialized);
3460
3484
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
3461
3485
  return provider;
3462
3486
  }
3463
3487
  }
3464
3488
  const localFallback = await createLocalFallbackProvider();
3465
3489
  if (localFallback) {
3466
- provider = wrapProvider(localFallback);
3490
+ provider = markProviderReady(localFallback);
3467
3491
  warnOnce(`[memorix] Embedding provider: ${provider.name} (${provider.dimensions}d)`);
3468
3492
  return provider;
3469
3493
  }
@@ -3485,6 +3509,27 @@ async function isVectorSearchAvailable() {
3485
3509
  const p = await getEmbeddingProvider();
3486
3510
  return p !== null;
3487
3511
  }
3512
+ function getEmbeddingRuntimeHealth() {
3513
+ const mode = getEmbeddingMode2();
3514
+ if (mode === "off") return { status: "disabled" };
3515
+ if (lastInitWasTemporaryFailure && lastEmbeddingFailure) {
3516
+ return {
3517
+ status: "degraded",
3518
+ failure: {
3519
+ kind: lastEmbeddingFailure.kind,
3520
+ occurredAt: new Date(lastEmbeddingFailure.occurredAt).toISOString(),
3521
+ retryAfterMs: Math.max(0, RETRY_COOLDOWN_MS - (Date.now() - lastEmbeddingFailure.occurredAt))
3522
+ }
3523
+ };
3524
+ }
3525
+ if (provider) {
3526
+ return {
3527
+ status: "ready",
3528
+ provider: { name: provider.name, dimensions: provider.dimensions }
3529
+ };
3530
+ }
3531
+ return { status: "uninitialized" };
3532
+ }
3488
3533
  function isEmbeddingExplicitlyDisabled() {
3489
3534
  return getEmbeddingMode2() === "off";
3490
3535
  }
@@ -3493,10 +3538,11 @@ function resetProvider() {
3493
3538
  initPromise = null;
3494
3539
  lastInitWasTemporaryFailure = false;
3495
3540
  lastFailureTimestamp = 0;
3541
+ lastEmbeddingFailure = null;
3496
3542
  lastEmbeddingWarning = "";
3497
3543
  lastEmbeddingWarningAt = 0;
3498
3544
  }
3499
- var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
3545
+ var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
3500
3546
  var init_provider = __esm({
3501
3547
  "src/embedding/provider.ts"() {
3502
3548
  "use strict";
@@ -3521,6 +3567,7 @@ var init_provider = __esm({
3521
3567
  provider = null;
3522
3568
  initPromise = null;
3523
3569
  lastInitWasTemporaryFailure = false;
3570
+ lastEmbeddingFailure = null;
3524
3571
  lastEmbeddingWarning = "";
3525
3572
  lastEmbeddingWarningAt = 0;
3526
3573
  WARNING_COOLDOWN_MS = 3e4;
@@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [1.6.1] - 2026-08-17
8
+
9
+ ### Fixed
10
+ - **Bounded hook lifecycle on every desktop platform** -- `memorix hook` now
11
+ reads stdin with an idle bound, performs embedding writes in the deferred
12
+ lane, and has a hard process deadline. The hook-specific V8 heap is 512 MiB
13
+ instead of the control plane's 4 GiB. This prevents hung hook processes and
14
+ associated CPU or memory pressure on macOS, Windows, and Linux. The Windows
15
+ CLI heap restart also hides its child console window.
16
+ - **Recoverable HTTP MCP sessions** -- HTTP MCP sessions now default to a
17
+ 12-hour idle window. An expired or unknown session receives a fast `404`
18
+ with a reinitialize hint instead of looking like a silent client hang. Set
19
+ `MEMORIX_SESSION_TIMEOUT_MS=0` only when the host owns lifecycle cleanup.
20
+ - **Truthful embedding diagnostics** -- the HTTP control plane exposes its
21
+ real runtime embedding state. `memorix doctor` reads that state instead of
22
+ reporting a fresh local probe as ready while the running service is degraded
23
+ by authorization, billing, timeout, or upstream failure.
24
+ - **Accurate doctor JSON health** -- a live PID with an unreachable HTTP
25
+ control plane now reports `healthy: false` rather than a false positive.
26
+
27
+ ### Changed
28
+ - **macOS release coverage** -- normal CI now runs the full build and test
29
+ suite on `macos-latest` in addition to Ubuntu and Windows.
30
+
7
31
  ## [1.6.0] - 2026-08-17
8
32
 
9
33
  ### Added