@remnic/core 9.3.651 → 9.3.652

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 (76) hide show
  1. package/dist/access-cli.js +9 -9
  2. package/dist/access-http.d.ts +3 -2
  3. package/dist/access-http.js +10 -10
  4. package/dist/access-mcp.d.ts +3 -2
  5. package/dist/access-mcp.js +9 -9
  6. package/dist/{access-service-DIZRHQ7Q.d.ts → access-service-CdJFd3_b.d.ts} +23 -2
  7. package/dist/access-service.d.ts +3 -2
  8. package/dist/access-service.js +8 -8
  9. package/dist/bootstrap.d.ts +2 -1
  10. package/dist/{chunk-QT4THOLT.js → chunk-2DGQLOOM.js} +1 -1
  11. package/dist/chunk-2DGQLOOM.js.map +1 -0
  12. package/dist/{chunk-SLYD3AH4.js → chunk-5V3TAB7D.js} +176 -4
  13. package/dist/chunk-5V3TAB7D.js.map +1 -0
  14. package/dist/{chunk-FOVPSMGI.js → chunk-7WEB3FLJ.js} +2 -2
  15. package/dist/{chunk-WJK75OCH.js → chunk-GI45G4BK.js} +2 -2
  16. package/dist/{chunk-76QTEJ2Q.js → chunk-JBHXMCYN.js} +2 -2
  17. package/dist/{chunk-4PTKFBST.js → chunk-JVRPJ7D4.js} +126 -26
  18. package/dist/chunk-JVRPJ7D4.js.map +1 -0
  19. package/dist/{chunk-TQUWNX7C.js → chunk-JX2RINDR.js} +2 -2
  20. package/dist/{chunk-RSS2KWN6.js → chunk-MGGNV3H2.js} +2 -2
  21. package/dist/{chunk-I4COC5XW.js → chunk-PYWNNF2I.js} +47 -9
  22. package/dist/chunk-PYWNNF2I.js.map +1 -0
  23. package/dist/{chunk-5WSDHTBO.js → chunk-TCX4WLKK.js} +7 -4
  24. package/dist/chunk-TCX4WLKK.js.map +1 -0
  25. package/dist/{chunk-RKN5J4RO.js → chunk-WSFNYPAT.js} +6 -6
  26. package/dist/{chunk-LFTLXOFX.js → chunk-WTI35CVJ.js} +2 -2
  27. package/dist/{chunk-6UKL6IXM.js → chunk-YM3LR4LS.js} +5 -5
  28. package/dist/{chunk-MF32AL7N.js → chunk-YOVKPOMD.js} +3 -3
  29. package/dist/{cli-BG4ybtJr.d.ts → cli-DDo7Qgs-.d.ts} +2 -2
  30. package/dist/cli.d.ts +4 -3
  31. package/dist/cli.js +13 -13
  32. package/dist/explicit-capture.d.ts +2 -1
  33. package/dist/index.d.ts +5 -4
  34. package/dist/index.js +14 -14
  35. package/dist/mcp-memory-inspector-app.d.ts +3 -2
  36. package/dist/namespaces/migrate.js +8 -8
  37. package/dist/namespaces/search.d.ts +18 -1
  38. package/dist/namespaces/search.js +7 -7
  39. package/dist/operator-toolkit.js +9 -9
  40. package/dist/{orchestrator-CX-oqwJq.d.ts → orchestrator-8fTZsa0y.d.ts} +2 -0
  41. package/dist/orchestrator.d.ts +2 -1
  42. package/dist/orchestrator.js +8 -8
  43. package/dist/qmd.d.ts +2 -1
  44. package/dist/qmd.js +2 -2
  45. package/dist/schemas.d.ts +22 -22
  46. package/dist/search/factory.js +6 -6
  47. package/dist/search/index.js +6 -6
  48. package/dist/search/lancedb-backend.js +2 -2
  49. package/dist/search/meilisearch-backend.js +2 -2
  50. package/dist/search/orama-backend.js +2 -2
  51. package/dist/search/port.d.ts +6 -0
  52. package/dist/search/port.js +1 -1
  53. package/dist/transfer/types.d.ts +12 -12
  54. package/package.json +1 -1
  55. package/src/access-service-health.test.ts +402 -0
  56. package/src/access-service.ts +274 -2
  57. package/src/namespaces/search.test.ts +258 -3
  58. package/src/namespaces/search.ts +184 -30
  59. package/src/orchestrator.ts +11 -1
  60. package/src/qmd.test.ts +102 -0
  61. package/src/qmd.ts +54 -7
  62. package/src/search/port.ts +6 -0
  63. package/dist/chunk-4PTKFBST.js.map +0 -1
  64. package/dist/chunk-5WSDHTBO.js.map +0 -1
  65. package/dist/chunk-I4COC5XW.js.map +0 -1
  66. package/dist/chunk-QT4THOLT.js.map +0 -1
  67. package/dist/chunk-SLYD3AH4.js.map +0 -1
  68. /package/dist/{chunk-FOVPSMGI.js.map → chunk-7WEB3FLJ.js.map} +0 -0
  69. /package/dist/{chunk-WJK75OCH.js.map → chunk-GI45G4BK.js.map} +0 -0
  70. /package/dist/{chunk-76QTEJ2Q.js.map → chunk-JBHXMCYN.js.map} +0 -0
  71. /package/dist/{chunk-TQUWNX7C.js.map → chunk-JX2RINDR.js.map} +0 -0
  72. /package/dist/{chunk-RSS2KWN6.js.map → chunk-MGGNV3H2.js.map} +0 -0
  73. /package/dist/{chunk-RKN5J4RO.js.map → chunk-WSFNYPAT.js.map} +0 -0
  74. /package/dist/{chunk-LFTLXOFX.js.map → chunk-WTI35CVJ.js.map} +0 -0
  75. /package/dist/{chunk-6UKL6IXM.js.map → chunk-YM3LR4LS.js.map} +0 -0
  76. /package/dist/{chunk-MF32AL7N.js.map → chunk-YOVKPOMD.js.map} +0 -0
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-CINZGPSJ.js";
8
8
  import {
9
9
  resolveEnsureCollectionArgs
10
- } from "./chunk-QT4THOLT.js";
10
+ } from "./chunk-2DGQLOOM.js";
11
11
  import {
12
12
  log
13
13
  } from "./chunk-2ODBA7MQ.js";
@@ -491,4 +491,4 @@ function isMissingVectorProviderColumnError(err) {
491
491
  export {
492
492
  LanceDbBackend
493
493
  };
494
- //# sourceMappingURL=chunk-FOVPSMGI.js.map
494
+ //# sourceMappingURL=chunk-7WEB3FLJ.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-ORGWWNJG.js";
4
4
  import {
5
5
  namespaceCollectionName
6
- } from "./chunk-4PTKFBST.js";
6
+ } from "./chunk-JVRPJ7D4.js";
7
7
  import {
8
8
  namespaceIdentityFromToken,
9
9
  namespaceIdentityToken
@@ -204,4 +204,4 @@ export {
204
204
  verifyNamespaces,
205
205
  runNamespaceMigration
206
206
  };
207
- //# sourceMappingURL=chunk-WJK75OCH.js.map
207
+ //# sourceMappingURL=chunk-GI45G4BK.js.map
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-CINZGPSJ.js";
8
8
  import {
9
9
  resolveEnsureCollectionArgs
10
- } from "./chunk-QT4THOLT.js";
10
+ } from "./chunk-2DGQLOOM.js";
11
11
  import {
12
12
  log
13
13
  } from "./chunk-2ODBA7MQ.js";
@@ -605,4 +605,4 @@ export {
605
605
  resolveOramaCollectionDbFilePath,
606
606
  OramaBackend
607
607
  };
608
- //# sourceMappingURL=chunk-76QTEJ2Q.js.map
608
+ //# sourceMappingURL=chunk-JBHXMCYN.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createSearchBackend
3
- } from "./chunk-6UKL6IXM.js";
3
+ } from "./chunk-YM3LR4LS.js";
4
4
  import {
5
5
  namespaceIdentityToken,
6
6
  normalizeNamespaceIdentity
@@ -125,6 +125,50 @@ var NamespaceSearchRouter = class {
125
125
  const record = await this.backendRecordFor(namespace, execution);
126
126
  return record.collectionState;
127
127
  }
128
+ async healthForNamespace(namespace, execution) {
129
+ const key = namespace.trim() || this.config.defaultNamespace;
130
+ const record = await this.createBackendRecordFor(
131
+ key,
132
+ execution,
133
+ {
134
+ autoCreateCollection: false,
135
+ abortAsUnavailable: true,
136
+ failOpenMissingGuardedCollection: false
137
+ }
138
+ );
139
+ try {
140
+ const liveRecord = await this.liveCachedRecordForHealth(key, record, execution);
141
+ const diagnosticBackend = liveRecord?.backend ?? record.backend;
142
+ const versionStatus = "getVersionStatus" in diagnosticBackend && typeof diagnosticBackend.getVersionStatus === "function" ? diagnosticBackend.getVersionStatus() : null;
143
+ const daemonMode = daemonModeForBackend(diagnosticBackend);
144
+ const collectionState = liveRecord?.collectionState === "missing" ? "missing" : record.collectionState;
145
+ return {
146
+ collection: record.collection,
147
+ memoryDir: record.memoryDir,
148
+ available: liveRecord?.available ?? record.available,
149
+ collectionState,
150
+ debugStatus: diagnosticBackend.debugStatus(),
151
+ installedVersion: versionStatus?.installedVersion ?? null,
152
+ supportedVersion: versionStatus?.supportedVersion ?? null,
153
+ supported: versionStatus?.supported ?? null,
154
+ upgradeAvailable: versionStatus?.upgradeAvailable ?? null,
155
+ doctorAvailable: versionStatus?.capabilities?.doctor ?? null,
156
+ daemonMode
157
+ };
158
+ } finally {
159
+ const dispose = record.backend.dispose;
160
+ await dispose?.call(record.backend);
161
+ }
162
+ }
163
+ async liveCachedRecordForHealth(key, disposableRecord, execution) {
164
+ const pending = this.cache.get(key);
165
+ if (!pending) return null;
166
+ const cachedRecord = await awaitWithAbort(pending, execution?.signal).catch(() => null);
167
+ if (!cachedRecord) return null;
168
+ if (cachedRecord.collection !== disposableRecord.collection) return null;
169
+ if (cachedRecord.memoryDir !== disposableRecord.memoryDir) return null;
170
+ return cachedRecord;
171
+ }
128
172
  /** Clear cached backend records so the next access re-probes availability. */
129
173
  clearCache() {
130
174
  this.cache.clear();
@@ -146,25 +190,54 @@ var NamespaceSearchRouter = class {
146
190
  const key = namespace.trim() || this.config.defaultNamespace;
147
191
  const existing = this.cache.get(key);
148
192
  if (existing) return await existing;
149
- const pending = (async () => {
150
- const storage = await this.storageRouter.storageFor(key);
151
- const useLegacyDefaultCollection = key === this.config.defaultNamespace && storage.dir === this.config.memoryDir;
152
- const filtersNestedNamespaces = this.config.namespacesEnabled === true && useLegacyDefaultCollection;
153
- const rootHostEmbeddingScope = this.config.hostEmbeddingProviderScope ?? this.config.memoryDir;
154
- const scopedConfig = {
155
- ...this.config,
156
- memoryDir: storage.dir,
157
- hostEmbeddingProviderScope: rootHostEmbeddingScope,
158
- qmdCollection: namespaceCollectionName(this.config.qmdCollection, key, {
159
- defaultNamespace: this.config.defaultNamespace,
160
- useLegacyDefaultCollection
161
- })
162
- };
163
- const backend = this.createBackend(scopedConfig);
164
- const available = await backend.probe().catch(() => false);
165
- const collectionState = available ? await this.collectionStateForBackend(backend, storage.dir, scopedConfig.qmdCollection, {
166
- skipAutoCreate: filtersNestedNamespaces,
167
- execution
193
+ const pending = this.createBackendRecordFor(key, execution, {
194
+ autoCreateCollection: true,
195
+ abortAsUnavailable: false,
196
+ failOpenMissingGuardedCollection: true
197
+ }).catch((error) => {
198
+ this.cache.delete(key);
199
+ throw error;
200
+ });
201
+ this.cache.set(key, pending);
202
+ return await pending;
203
+ }
204
+ async createBackendRecordFor(namespace, execution, options) {
205
+ const key = namespace.trim() || this.config.defaultNamespace;
206
+ const storage = await this.storageRouter.storageFor(key);
207
+ const useLegacyDefaultCollection = key === this.config.defaultNamespace && storage.dir === this.config.memoryDir;
208
+ const filtersNestedNamespaces = this.config.namespacesEnabled === true && useLegacyDefaultCollection;
209
+ const rootHostEmbeddingScope = this.config.hostEmbeddingProviderScope ?? this.config.memoryDir;
210
+ const scopedConfig = {
211
+ ...this.config,
212
+ memoryDir: storage.dir,
213
+ hostEmbeddingProviderScope: rootHostEmbeddingScope,
214
+ qmdCollection: namespaceCollectionName(this.config.qmdCollection, key, {
215
+ defaultNamespace: this.config.defaultNamespace,
216
+ useLegacyDefaultCollection
217
+ })
218
+ };
219
+ const backend = this.createBackend(scopedConfig);
220
+ try {
221
+ const availabilityProbe = options.autoCreateCollection || typeof backend.checkAvailability !== "function" ? backend.probe() : backend.checkAvailability({ signal: execution?.signal });
222
+ const available = await awaitWithAbort(availabilityProbe, execution?.signal).catch((error) => {
223
+ if (error instanceof NamespaceSearchAbortError && !options.abortAsUnavailable) {
224
+ throw error;
225
+ }
226
+ return false;
227
+ });
228
+ const collectionState = available ? await awaitWithAbort(
229
+ this.collectionStateForBackend(backend, storage.dir, scopedConfig.qmdCollection, {
230
+ autoCreate: options.autoCreateCollection,
231
+ failOpenMissingGuardedCollection: options.failOpenMissingGuardedCollection,
232
+ skipAutoCreate: filtersNestedNamespaces,
233
+ execution
234
+ }),
235
+ execution?.signal
236
+ ).catch((error) => {
237
+ if (error instanceof NamespaceSearchAbortError && !options.abortAsUnavailable) {
238
+ throw error;
239
+ }
240
+ return "unknown";
168
241
  }) : "unknown";
169
242
  return {
170
243
  backend,
@@ -174,19 +247,43 @@ var NamespaceSearchRouter = class {
174
247
  collectionState,
175
248
  filtersNestedNamespaces
176
249
  };
177
- })();
178
- this.cache.set(key, pending);
179
- return await pending;
250
+ } catch (error) {
251
+ const dispose = backend.dispose;
252
+ if (dispose) {
253
+ await Promise.resolve(dispose.call(backend)).catch(() => {
254
+ });
255
+ }
256
+ throw error;
257
+ }
180
258
  }
181
259
  async collectionStateForBackend(backend, memoryDir, collection, options) {
182
- if (options.skipAutoCreate) {
260
+ if (!options.autoCreate || options.skipAutoCreate) {
183
261
  if (!backend.checkCollection) return "unknown";
184
262
  const collectionState = await backend.checkCollection(collection, options.execution).catch(() => "unknown");
185
- return collectionState === "missing" ? "unknown" : collectionState;
263
+ return options.failOpenMissingGuardedCollection && collectionState === "missing" ? "unknown" : collectionState;
186
264
  }
187
265
  return await backend.ensureCollection(memoryDir, collection, options.execution).catch(() => "unknown");
188
266
  }
189
267
  };
268
+ var NamespaceSearchAbortError = class extends Error {
269
+ constructor() {
270
+ super("operation aborted");
271
+ }
272
+ };
273
+ function awaitWithAbort(operation, signal) {
274
+ if (!signal) return operation;
275
+ if (signal.aborted) return Promise.reject(new NamespaceSearchAbortError());
276
+ return new Promise((resolve, reject) => {
277
+ const onAbort = () => {
278
+ signal.removeEventListener("abort", onAbort);
279
+ reject(new NamespaceSearchAbortError());
280
+ };
281
+ signal.addEventListener("abort", onAbort, { once: true });
282
+ operation.then(resolve, reject).finally(() => {
283
+ signal.removeEventListener("abort", onAbort);
284
+ });
285
+ });
286
+ }
190
287
  function filterNamespaceSubtreeResults(record, results) {
191
288
  if (!record.filtersNestedNamespaces) return results;
192
289
  return results.filter(
@@ -201,6 +298,9 @@ function backendSearchLimit(record, maxResults) {
201
298
  NESTED_NAMESPACE_FILTER_OVERFETCH_MIN
202
299
  );
203
300
  }
301
+ function daemonModeForBackend(backend) {
302
+ return "isDaemonMode" in backend && typeof backend.isDaemonMode === "function" ? backend.isDaemonMode() === true : null;
303
+ }
204
304
  function pathIsInsideNamespaceSubtree(memoryDir, collection, resultPath) {
205
305
  if (!resultPath) return false;
206
306
  const normalizedResultPath = normalizeQmdResultPath(resultPath, collection);
@@ -257,4 +357,4 @@ export {
257
357
  namespaceCollectionName,
258
358
  NamespaceSearchRouter
259
359
  };
260
- //# sourceMappingURL=chunk-4PTKFBST.js.map
360
+ //# sourceMappingURL=chunk-JVRPJ7D4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/namespaces/search.ts"],"sourcesContent":["import path from \"node:path\";\nimport type { PluginConfig, QmdSearchResult } from \"../types.js\";\nimport type {\n SearchBackend,\n SearchExecutionOptions,\n SearchQueryOptions,\n} from \"../search/port.js\";\nimport { createSearchBackend } from \"../search/factory.js\";\nimport { namespaceIdentityToken, normalizeNamespaceIdentity } from \"./identity.js\";\n\nconst NESTED_NAMESPACE_FILTER_OVERFETCH_FACTOR = 4;\nconst NESTED_NAMESPACE_FILTER_OVERFETCH_MIN = 50;\n\nexport function namespaceCollectionName(\n baseCollection: string,\n namespace: string,\n options?: {\n defaultNamespace?: string;\n useLegacyDefaultCollection?: boolean;\n },\n): string {\n const trimmed = normalizeNamespaceIdentity(namespace);\n const defaultNamespace = normalizeNamespaceIdentity(options?.defaultNamespace ?? \"\") || \"default\";\n if (\n options?.useLegacyDefaultCollection === true &&\n trimmed === defaultNamespace\n ) {\n return baseCollection;\n }\n\n return `${baseCollection}--${namespaceIdentityToken(trimmed || defaultNamespace)}`;\n}\n\ntype StorageRouterLike = {\n storageFor(namespace: string): Promise<{ dir: string }>;\n};\n\ntype NamespaceBackendRecord = {\n backend: SearchBackend;\n collection: string;\n memoryDir: string;\n available: boolean;\n collectionState: CollectionState;\n filtersNestedNamespaces: boolean;\n};\n\nexport type CollectionState = \"present\" | \"missing\" | \"unknown\" | \"skipped\";\n\nexport interface NamespaceSearchHealth {\n collection: string;\n memoryDir: string;\n available: boolean;\n collectionState: CollectionState;\n debugStatus: string;\n installedVersion: string | null;\n supportedVersion: string | null;\n supported: boolean | null;\n upgradeAvailable: boolean | null;\n doctorAvailable: boolean | null;\n daemonMode: boolean | null;\n}\n\ntype NamespaceScopedSearchConfig = PluginConfig & {\n hostEmbeddingProviderScope?: string;\n};\n\ntype BackendRecordOptions = {\n autoCreateCollection: boolean;\n abortAsUnavailable: boolean;\n failOpenMissingGuardedCollection: boolean;\n};\n\nexport class NamespaceSearchRouter {\n private readonly cache = new Map<string, Promise<NamespaceBackendRecord>>();\n\n constructor(\n private readonly config: PluginConfig,\n private readonly storageRouter: StorageRouterLike,\n private readonly createBackend: (config: PluginConfig) => SearchBackend = createSearchBackend,\n ) {}\n\n async collectionForNamespace(namespace: string): Promise<string> {\n return (await this.backendRecordFor(namespace)).collection;\n }\n\n async searchAcrossNamespaces(options: {\n query: string;\n namespaces: string[];\n maxResults?: number;\n mode?: \"search\" | \"hybrid\" | \"bm25\" | \"vector\";\n searchOptions?: SearchQueryOptions;\n execution?: SearchExecutionOptions;\n }): Promise<QmdSearchResult[]> {\n const query = options.query.trim();\n if (!query) return [];\n const maxResults = Math.max(0, Math.floor(options.maxResults ?? this.config.qmdMaxResults));\n if (maxResults === 0) return [];\n\n const method = options.mode ?? \"search\";\n const namespaces = Array.from(new Set(options.namespaces.map((value) => value.trim()).filter(Boolean)));\n if (namespaces.length === 0) return [];\n\n const resultsByNamespace = await Promise.all(\n namespaces.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n if (!record.available || record.collectionState === \"missing\") {\n return { namespace, results: [] as QmdSearchResult[] };\n }\n const backendLimit = backendSearchLimit(record, maxResults);\n let results: QmdSearchResult[];\n switch (method) {\n case \"hybrid\":\n results = await record.backend.hybridSearch(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n case \"bm25\":\n results = await record.backend.bm25Search(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n case \"vector\":\n results = await record.backend.vectorSearch(\n query,\n record.collection,\n backendLimit,\n options.execution,\n );\n break;\n default:\n results = await record.backend.search(\n query,\n record.collection,\n backendLimit,\n options.searchOptions,\n options.execution,\n );\n break;\n }\n results = filterNamespaceSubtreeResults(record, results);\n return { namespace, results };\n }),\n );\n\n return mergeNamespaceSearchResults(resultsByNamespace, maxResults);\n }\n\n /**\n * Update all namespace backends.\n * Returns the number of backends for which an update was attempted\n * (i.e., available and collection present). Callers can treat 0 as a\n * signal that no backend was eligible — useful for success-verification in\n * startup-sync when namespacesEnabled is true.\n */\n async updateNamespaces(\n namespaces: string[],\n execution?: SearchExecutionOptions,\n ): Promise<number> {\n const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));\n const eligible = (await Promise.all(\n unique.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n return record.available && record.collectionState !== \"missing\"\n ? record\n : null;\n }),\n )).filter((record): record is NamespaceBackendRecord => record !== null);\n\n const globalRecord = eligible.find((record) => record.backend.updatesAllCollections?.() === true);\n const scopedRecords = globalRecord\n ? eligible.filter((record) => record.backend.updatesAllCollections?.() !== true)\n : eligible;\n\n await Promise.all([\n globalRecord ? globalRecord.backend.update(execution) : Promise.resolve(),\n ...scopedRecords.map((record) => record.backend.update(execution)),\n ]);\n\n return (globalRecord ? 1 : 0) + scopedRecords.length;\n }\n\n async embedNamespaces(namespaces: string[]): Promise<void> {\n const unique = Array.from(new Set(namespaces.map((value) => value.trim()).filter(Boolean)));\n await Promise.all(\n unique.map(async (namespace) => {\n const record = await this.backendRecordFor(namespace);\n if (!record.available || record.collectionState === \"missing\") return;\n await record.backend.embed();\n }),\n );\n }\n\n async ensureNamespaceCollection(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<\"present\" | \"missing\" | \"unknown\" | \"skipped\"> {\n const record = await this.backendRecordFor(namespace, execution);\n return record.collectionState;\n }\n\n async healthForNamespace(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceSearchHealth> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const record = await this.createBackendRecordFor(\n key,\n execution,\n {\n autoCreateCollection: false,\n abortAsUnavailable: true,\n failOpenMissingGuardedCollection: false,\n },\n );\n try {\n const liveRecord = await this.liveCachedRecordForHealth(key, record, execution);\n const diagnosticBackend = liveRecord?.backend ?? record.backend;\n const versionStatus =\n \"getVersionStatus\" in diagnosticBackend &&\n typeof diagnosticBackend.getVersionStatus === \"function\"\n ? diagnosticBackend.getVersionStatus()\n : null;\n const daemonMode = daemonModeForBackend(diagnosticBackend);\n const collectionState =\n liveRecord?.collectionState === \"missing\"\n ? \"missing\"\n : record.collectionState;\n\n return {\n collection: record.collection,\n memoryDir: record.memoryDir,\n available: liveRecord?.available ?? record.available,\n collectionState,\n debugStatus: diagnosticBackend.debugStatus(),\n installedVersion: versionStatus?.installedVersion ?? null,\n supportedVersion: versionStatus?.supportedVersion ?? null,\n supported: versionStatus?.supported ?? null,\n upgradeAvailable: versionStatus?.upgradeAvailable ?? null,\n doctorAvailable: versionStatus?.capabilities?.doctor ?? null,\n daemonMode,\n };\n } finally {\n const dispose = (record.backend as { dispose?: () => void | Promise<void> }).dispose;\n await dispose?.call(record.backend);\n }\n }\n\n private async liveCachedRecordForHealth(\n key: string,\n disposableRecord: NamespaceBackendRecord,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceBackendRecord | null> {\n const pending = this.cache.get(key);\n if (!pending) return null;\n const cachedRecord = await awaitWithAbort(pending, execution?.signal).catch(() => null);\n if (!cachedRecord) return null;\n if (cachedRecord.collection !== disposableRecord.collection) return null;\n if (cachedRecord.memoryDir !== disposableRecord.memoryDir) return null;\n return cachedRecord;\n }\n\n /** Clear cached backend records so the next access re-probes availability. */\n clearCache(): void {\n this.cache.clear();\n }\n\n /** Release any per-namespace backend handles held by cached records. */\n async dispose(): Promise<void> {\n const pendingRecords = Array.from(this.cache.values());\n this.cache.clear();\n const settled = await Promise.allSettled(pendingRecords);\n await Promise.allSettled(\n settled.flatMap((entry) => {\n if (entry.status !== \"fulfilled\") return [];\n const dispose = (entry.value.backend as { dispose?: () => void | Promise<void> }).dispose;\n return dispose ? [dispose.call(entry.value.backend)] : [];\n }),\n );\n }\n\n private async backendRecordFor(\n namespace: string,\n execution?: SearchExecutionOptions,\n ): Promise<NamespaceBackendRecord> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const existing = this.cache.get(key);\n if (existing) return await existing;\n\n const pending = this.createBackendRecordFor(key, execution, {\n autoCreateCollection: true,\n abortAsUnavailable: false,\n failOpenMissingGuardedCollection: true,\n }).catch((error) => {\n this.cache.delete(key);\n throw error;\n });\n\n this.cache.set(key, pending);\n return await pending;\n }\n\n private async createBackendRecordFor(\n namespace: string,\n execution: SearchExecutionOptions | undefined,\n options: BackendRecordOptions,\n ): Promise<NamespaceBackendRecord> {\n const key = namespace.trim() || this.config.defaultNamespace;\n const storage = await this.storageRouter.storageFor(key);\n const useLegacyDefaultCollection =\n key === this.config.defaultNamespace && storage.dir === this.config.memoryDir;\n const filtersNestedNamespaces =\n this.config.namespacesEnabled === true && useLegacyDefaultCollection;\n const rootHostEmbeddingScope =\n (this.config as NamespaceScopedSearchConfig).hostEmbeddingProviderScope ??\n this.config.memoryDir;\n const scopedConfig: NamespaceScopedSearchConfig = {\n ...this.config,\n memoryDir: storage.dir,\n hostEmbeddingProviderScope: rootHostEmbeddingScope,\n qmdCollection: namespaceCollectionName(this.config.qmdCollection, key, {\n defaultNamespace: this.config.defaultNamespace,\n useLegacyDefaultCollection,\n }),\n };\n\n const backend = this.createBackend(scopedConfig);\n try {\n const availabilityProbe =\n options.autoCreateCollection || typeof backend.checkAvailability !== \"function\"\n ? backend.probe()\n : backend.checkAvailability({ signal: execution?.signal });\n const available = await awaitWithAbort(availabilityProbe, execution?.signal).catch((error) => {\n if (error instanceof NamespaceSearchAbortError && !options.abortAsUnavailable) {\n throw error;\n }\n return false;\n });\n const collectionState = available\n ? await awaitWithAbort(\n this.collectionStateForBackend(backend, storage.dir, scopedConfig.qmdCollection, {\n autoCreate: options.autoCreateCollection,\n failOpenMissingGuardedCollection: options.failOpenMissingGuardedCollection,\n skipAutoCreate: filtersNestedNamespaces,\n execution,\n }),\n execution?.signal,\n ).catch((error) => {\n if (error instanceof NamespaceSearchAbortError && !options.abortAsUnavailable) {\n throw error;\n }\n return \"unknown\" as const;\n })\n : \"unknown\";\n return {\n backend,\n collection: scopedConfig.qmdCollection,\n memoryDir: storage.dir,\n available,\n collectionState,\n filtersNestedNamespaces,\n };\n } catch (error) {\n const dispose = (backend as { dispose?: () => void | Promise<void> }).dispose;\n if (dispose) {\n await Promise.resolve(dispose.call(backend)).catch(() => {});\n }\n throw error;\n }\n }\n\n private async collectionStateForBackend(\n backend: SearchBackend,\n memoryDir: string,\n collection: string,\n options: {\n autoCreate: boolean;\n failOpenMissingGuardedCollection: boolean;\n skipAutoCreate: boolean;\n execution?: SearchExecutionOptions;\n },\n ): Promise<CollectionState> {\n if (!options.autoCreate || options.skipAutoCreate) {\n if (!backend.checkCollection) return \"unknown\";\n const collectionState = await backend\n .checkCollection(collection, options.execution)\n .catch(() => \"unknown\" as const);\n return options.failOpenMissingGuardedCollection && collectionState === \"missing\"\n ? \"unknown\"\n : collectionState;\n }\n return await backend.ensureCollection(memoryDir, collection, options.execution).catch(() => \"unknown\" as const);\n }\n}\n\nclass NamespaceSearchAbortError extends Error {\n constructor() {\n super(\"operation aborted\");\n }\n}\n\nfunction awaitWithAbort<T>(operation: Promise<T>, signal?: AbortSignal): Promise<T> {\n if (!signal) return operation;\n if (signal.aborted) return Promise.reject(new NamespaceSearchAbortError());\n\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n signal.removeEventListener(\"abort\", onAbort);\n reject(new NamespaceSearchAbortError());\n };\n signal.addEventListener(\"abort\", onAbort, { once: true });\n operation.then(resolve, reject).finally(() => {\n signal.removeEventListener(\"abort\", onAbort);\n });\n });\n}\n\nfunction filterNamespaceSubtreeResults(\n record: NamespaceBackendRecord,\n results: QmdSearchResult[],\n): QmdSearchResult[] {\n if (!record.filtersNestedNamespaces) return results;\n return results.filter((result) =>\n !pathIsInsideNamespaceSubtree(record.memoryDir, record.collection, result.path)\n );\n}\n\nfunction backendSearchLimit(\n record: NamespaceBackendRecord,\n maxResults: number,\n): number {\n if (!record.filtersNestedNamespaces) return maxResults;\n return Math.max(\n maxResults,\n maxResults * NESTED_NAMESPACE_FILTER_OVERFETCH_FACTOR,\n NESTED_NAMESPACE_FILTER_OVERFETCH_MIN,\n );\n}\n\nfunction daemonModeForBackend(backend: SearchBackend): boolean | null {\n return \"isDaemonMode\" in backend && typeof backend.isDaemonMode === \"function\"\n ? backend.isDaemonMode() === true\n : null;\n}\n\nfunction pathIsInsideNamespaceSubtree(\n memoryDir: string,\n collection: string,\n resultPath: string | undefined,\n): boolean {\n if (!resultPath) return false;\n const normalizedResultPath = normalizeQmdResultPath(resultPath, collection);\n const memoryRoot = path.resolve(memoryDir);\n const namespacesRoot = path.join(memoryRoot, \"namespaces\");\n const candidate = path.isAbsolute(normalizedResultPath)\n ? path.normalize(normalizedResultPath)\n : path.resolve(memoryRoot, normalizedResultPath);\n const relative = path.relative(namespacesRoot, candidate);\n return relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative));\n}\n\nfunction normalizeQmdResultPath(resultPath: string, collection: string): string {\n let value = resultPath.trim();\n if (value.startsWith(\"qmd://\")) {\n try {\n const parsed = new URL(value);\n if (parsed.protocol === \"qmd:\" && parsed.hostname === collection) {\n value = decodeURIComponent(parsed.pathname.replace(/^\\/+/, \"\"));\n }\n } catch {\n const remainder = value.slice(\"qmd://\".length);\n const slashIndex = remainder.indexOf(\"/\");\n if (slashIndex !== -1) {\n value = remainder.slice(slashIndex + 1);\n }\n }\n }\n\n const collectionPrefix = `${collection}/`;\n if (value.startsWith(collectionPrefix)) {\n value = value.slice(collectionPrefix.length);\n }\n return value;\n}\n\nfunction mergeNamespaceSearchResults(\n lists: Array<{ namespace: string; results: QmdSearchResult[] }>,\n maxResults: number,\n): QmdSearchResult[] {\n const merged = new Map<string, QmdSearchResult>();\n\n for (const { namespace, results } of lists) {\n for (const result of results) {\n const key = `${namespace}\\0${result.path || result.docid}`;\n const existing = merged.get(key);\n if (!existing) {\n merged.set(key, result);\n continue;\n }\n if (result.score > existing.score) {\n merged.set(key, {\n ...result,\n snippet: existing.snippet || result.snippet || \"\",\n });\n }\n }\n }\n\n return [...merged.values()]\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults);\n}\n"],"mappings":"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","names":[]}
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-CINZGPSJ.js";
8
8
  import {
9
9
  resolveEnsureCollectionArgs
10
- } from "./chunk-QT4THOLT.js";
10
+ } from "./chunk-2DGQLOOM.js";
11
11
  import {
12
12
  log
13
13
  } from "./chunk-2ODBA7MQ.js";
@@ -245,4 +245,4 @@ function isMeilisearchIndexNotFoundError(err) {
245
245
  export {
246
246
  MeilisearchBackend
247
247
  };
248
- //# sourceMappingURL=chunk-TQUWNX7C.js.map
248
+ //# sourceMappingURL=chunk-JX2RINDR.js.map
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-D24OXEPB.js";
12
12
  import {
13
13
  EngramAccessInputError
14
- } from "./chunk-SLYD3AH4.js";
14
+ } from "./chunk-5V3TAB7D.js";
15
15
  import {
16
16
  projectTagProjectId
17
17
  } from "./chunk-MMJANTJX.js";
@@ -3102,4 +3102,4 @@ ${body}`;
3102
3102
  export {
3103
3103
  EngramMcpServer
3104
3104
  };
3105
- //# sourceMappingURL=chunk-RSS2KWN6.js.map
3105
+ //# sourceMappingURL=chunk-MGGNV3H2.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveEnsureCollectionArgs
3
- } from "./chunk-QT4THOLT.js";
3
+ } from "./chunk-2DGQLOOM.js";
4
4
  import {
5
5
  launchProcess
6
6
  } from "./chunk-O75CRYGF.js";
@@ -941,6 +941,21 @@ var QmdClient = class _QmdClient {
941
941
  }
942
942
  return cliOk || this.daemonAvailable;
943
943
  }
944
+ async checkAvailability(execution) {
945
+ const cliAvailable = await this.probeCli({
946
+ allowAutoUpgrade: false,
947
+ preserveStateOnFailure: true,
948
+ signal: execution?.signal
949
+ });
950
+ if (this.daemonAvailable && this.daemonSession?.isActive()) {
951
+ return true;
952
+ }
953
+ if (this.daemonAvailable) {
954
+ this.daemonAvailable = false;
955
+ this.lastDaemonCheckAtMs = 0;
956
+ }
957
+ return cliAvailable;
958
+ }
944
959
  async probeDaemon() {
945
960
  this.lastDaemonCheckAtMs = Date.now();
946
961
  const normalizedPath = this.qmdPath.trim() || "qmd";
@@ -978,7 +993,24 @@ var QmdClient = class _QmdClient {
978
993
  return false;
979
994
  }
980
995
  }
981
- async probeCli() {
996
+ async probeCli(options = {}) {
997
+ const priorState = options.preserveStateOnFailure === true ? {
998
+ available: this.available,
999
+ qmdPath: this.qmdPath,
1000
+ qmdPathSource: this.qmdPathSource,
1001
+ cliVersion: this.cliVersion,
1002
+ lastCliProbeError: this.lastCliProbeError,
1003
+ qmdCapabilities: this.qmdCapabilities
1004
+ } : null;
1005
+ const restorePriorState = () => {
1006
+ if (!priorState) return;
1007
+ this.available = priorState.available;
1008
+ this.qmdPath = priorState.qmdPath;
1009
+ this.qmdPathSource = priorState.qmdPathSource;
1010
+ this.cliVersion = priorState.cliVersion;
1011
+ this.lastCliProbeError = priorState.lastCliProbeError;
1012
+ this.qmdCapabilities = priorState.qmdCapabilities;
1013
+ };
982
1014
  let configuredProbeFailure = null;
983
1015
  const markProbeFailure = (err) => {
984
1016
  this.lastCliProbeError = err instanceof Error ? err.message : String(err);
@@ -996,11 +1028,13 @@ var QmdClient = class _QmdClient {
996
1028
  this.cliVersion = parseQmdVersionOutput(result.stdout, result.stderr);
997
1029
  this.qmdCapabilities = resolveQmdCapabilities(this.cliVersion);
998
1030
  this.lastCliProbeError = null;
999
- await this.maybeAutoUpgradeQmd();
1031
+ if (options.allowAutoUpgrade !== false) {
1032
+ await this.maybeAutoUpgradeQmd();
1033
+ }
1000
1034
  };
1001
1035
  if (this.configuredQmdPath) {
1002
1036
  try {
1003
- const result = await runQmd(["--version"], QMD_PROBE_TIMEOUT_MS, this.configuredQmdPath, void 0, this.qmdRuntimeEnv);
1037
+ const result = await runQmd(["--version"], QMD_PROBE_TIMEOUT_MS, this.configuredQmdPath, options.signal, this.qmdRuntimeEnv);
1004
1038
  await recordProbeSuccess(result, this.configuredQmdPath, "configured");
1005
1039
  return true;
1006
1040
  } catch (err) {
@@ -1012,14 +1046,14 @@ var QmdClient = class _QmdClient {
1012
1046
  }
1013
1047
  }
1014
1048
  try {
1015
- const result = await runQmd(["--version"], QMD_PROBE_TIMEOUT_MS, "qmd", void 0, this.qmdRuntimeEnv);
1049
+ const result = await runQmd(["--version"], QMD_PROBE_TIMEOUT_MS, "qmd", options.signal, this.qmdRuntimeEnv);
1016
1050
  await recordProbeSuccess(result, "qmd", "auto-path");
1017
1051
  return true;
1018
1052
  } catch (err) {
1019
1053
  markProbeFailure(err);
1020
1054
  for (const fallbackPath of this.qmdFallbackPaths) {
1021
1055
  try {
1022
- const result = await runQmd(["--version"], QMD_PROBE_TIMEOUT_MS, fallbackPath, void 0, this.qmdRuntimeEnv);
1056
+ const result = await runQmd(["--version"], QMD_PROBE_TIMEOUT_MS, fallbackPath, options.signal, this.qmdRuntimeEnv);
1023
1057
  await recordProbeSuccess(result, fallbackPath, "auto-fallback");
1024
1058
  log.info(`QMD: found at ${fallbackPath}`);
1025
1059
  return true;
@@ -1027,8 +1061,12 @@ var QmdClient = class _QmdClient {
1027
1061
  markProbeFailure(fallbackErr);
1028
1062
  }
1029
1063
  }
1030
- this.available = false;
1031
- restoreConfiguredProbeFailure();
1064
+ if (priorState) {
1065
+ restorePriorState();
1066
+ } else {
1067
+ this.available = false;
1068
+ restoreConfiguredProbeFailure();
1069
+ }
1032
1070
  return false;
1033
1071
  }
1034
1072
  }
@@ -2065,4 +2103,4 @@ export {
2065
2103
  getQmdCommandName,
2066
2104
  QmdClient
2067
2105
  };
2068
- //# sourceMappingURL=chunk-I4COC5XW.js.map
2106
+ //# sourceMappingURL=chunk-PYWNNF2I.js.map