@soulcraft/cor 3.0.0-rc.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 (87) hide show
  1. package/LICENSE +16 -0
  2. package/README.md +328 -0
  3. package/dist/aggregation/NativeAggregationEngine.d.ts +118 -0
  4. package/dist/aggregation/NativeAggregationEngine.js +186 -0
  5. package/dist/cli.d.ts +12 -0
  6. package/dist/cli.js +236 -0
  7. package/dist/graph/GraphAccelerationAdapter.d.ts +153 -0
  8. package/dist/graph/GraphAccelerationAdapter.js +326 -0
  9. package/dist/graph/NativeGraphAdjacencyIndex.d.ts +286 -0
  10. package/dist/graph/NativeGraphAdjacencyIndex.js +944 -0
  11. package/dist/hnsw/AdaptiveDiskAnnModeSelector.d.ts +187 -0
  12. package/dist/hnsw/AdaptiveDiskAnnModeSelector.js +313 -0
  13. package/dist/hnsw/NativeDiskAnnWrapper.d.ts +489 -0
  14. package/dist/hnsw/NativeDiskAnnWrapper.js +1456 -0
  15. package/dist/index.d.ts +28 -0
  16. package/dist/index.js +29 -0
  17. package/dist/legacyLayoutGuard.d.ts +93 -0
  18. package/dist/legacyLayoutGuard.js +237 -0
  19. package/dist/license/constants.d.ts +30 -0
  20. package/dist/license/constants.js +30 -0
  21. package/dist/license/onlineValidator.d.ts +43 -0
  22. package/dist/license/onlineValidator.js +225 -0
  23. package/dist/license/types.d.ts +39 -0
  24. package/dist/license/types.js +5 -0
  25. package/dist/license.d.ts +64 -0
  26. package/dist/license.js +165 -0
  27. package/dist/migration/MigrationCoordinator.d.ts +171 -0
  28. package/dist/migration/MigrationCoordinator.js +249 -0
  29. package/dist/migration/indexEpochGuard.d.ts +163 -0
  30. package/dist/migration/indexEpochGuard.js +202 -0
  31. package/dist/native/NativeEmbeddingEngine.d.ts +79 -0
  32. package/dist/native/NativeEmbeddingEngine.js +318 -0
  33. package/dist/native/NativeRoaringBitmap32.d.ts +114 -0
  34. package/dist/native/NativeRoaringBitmap32.js +221 -0
  35. package/dist/native/ffi.d.ts +20 -0
  36. package/dist/native/ffi.js +48 -0
  37. package/dist/native/idMapperTestSupport.d.ts +67 -0
  38. package/dist/native/idMapperTestSupport.js +112 -0
  39. package/dist/native/index.d.ts +49 -0
  40. package/dist/native/index.js +87 -0
  41. package/dist/native/napi.d.ts +21 -0
  42. package/dist/native/napi.js +88 -0
  43. package/dist/native/types.d.ts +1298 -0
  44. package/dist/native/types.js +16 -0
  45. package/dist/plugin.d.ts +50 -0
  46. package/dist/plugin.js +388 -0
  47. package/dist/providerContracts.d.ts +277 -0
  48. package/dist/providerContracts.js +38 -0
  49. package/dist/resource/OsMemoryProbe.d.ts +175 -0
  50. package/dist/resource/OsMemoryProbe.js +206 -0
  51. package/dist/resource/ResourceManager.d.ts +491 -0
  52. package/dist/resource/ResourceManager.js +960 -0
  53. package/dist/utils/ColumnManifest.d.ts +97 -0
  54. package/dist/utils/ColumnManifest.js +129 -0
  55. package/dist/utils/NativeColumnStore.d.ts +284 -0
  56. package/dist/utils/NativeColumnStore.js +685 -0
  57. package/dist/utils/NativeMetadataIndex.d.ts +882 -0
  58. package/dist/utils/NativeMetadataIndex.js +2631 -0
  59. package/dist/utils/NativeUnifiedCache.d.ts +87 -0
  60. package/dist/utils/NativeUnifiedCache.js +273 -0
  61. package/dist/utils/binaryIdMapperFactory.d.ts +59 -0
  62. package/dist/utils/binaryIdMapperFactory.js +94 -0
  63. package/dist/utils/collation.d.ts +30 -0
  64. package/dist/utils/collation.js +40 -0
  65. package/dist/utils/columnStoreTypes.d.ts +161 -0
  66. package/dist/utils/columnStoreTypes.js +29 -0
  67. package/dist/utils/nativeBinaryEntityIdMapper.d.ts +211 -0
  68. package/dist/utils/nativeBinaryEntityIdMapper.js +381 -0
  69. package/dist/utils/nativeEntityIdMapper.d.ts +111 -0
  70. package/dist/utils/nativeEntityIdMapper.js +170 -0
  71. package/docs/ADR-002-diskann-100-percent-rust.md +294 -0
  72. package/docs/ADR-003-semantic-time-travel.md +100 -0
  73. package/docs/aggregation.md +251 -0
  74. package/docs/comparison.md +162 -0
  75. package/docs/deployment-limits.md +87 -0
  76. package/docs/diskann.md +184 -0
  77. package/docs/migration-3.0.md +396 -0
  78. package/docs/performance-budget.md +274 -0
  79. package/docs/performance.md +117 -0
  80. package/docs/scaling.md +439 -0
  81. package/docs/snapshot-safety.md +246 -0
  82. package/docs/u64-id-space.md +214 -0
  83. package/docs/verification-report.md +670 -0
  84. package/native/brainy-native.node +0 -0
  85. package/native/index.d.ts +3916 -0
  86. package/package.json +92 -0
  87. package/scripts/migrate-cortex-2x-to-3x.mjs +970 -0
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Shared types for the native module integration.
3
+ *
4
+ * These types are used by both the napi-rs and bun:ffi loaders.
5
+ * Ported from src/embeddings/wasm/types.ts — keeps the same API surface.
6
+ */
7
+ /**
8
+ * Model constants for all-MiniLM-L6-v2
9
+ */
10
+ export const MODEL_CONSTANTS = {
11
+ HIDDEN_SIZE: 384,
12
+ MAX_SEQUENCE_LENGTH: 256,
13
+ VOCAB_SIZE: 30522,
14
+ MODEL_NAME: 'all-MiniLM-L6-v2',
15
+ };
16
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @module plugin
3
+ * @description `@soulcraft/cor` Brainy plugin entry point.
4
+ *
5
+ * Implements the `BrainyPlugin` interface to register every native
6
+ * provider cor 3.0 ships. Brainy auto-detects this plugin during
7
+ * `init()` via dynamic import.
8
+ *
9
+ * ## Tier gating
10
+ *
11
+ * - **Free tier (no license key)**: nothing registered — brainy runs
12
+ * on its pure-JS defaults with zero acceleration.
13
+ * - **Pro / Enterprise / Internal**: every compute provider below
14
+ * wired in. Cor is a pure 1:1 accelerator — it registers ONLY
15
+ * the providers brainy currently looks up; native capabilities
16
+ * that don't yet have a brainy hook stay dormant in the cdylib.
17
+ *
18
+ * ## Cor 3.0 surface (Piece F, 2026-06-09)
19
+ *
20
+ * | Provider | Implementation |
21
+ * |-------------------|---------------------------------------------|
22
+ * | `distance` | SIMD-accelerated cosine |
23
+ * | `distance:sq8` | SQ8 quantized cosine (uint8) |
24
+ * | `distance:sq4` | SQ4 quantized cosine (packed nibbles) |
25
+ * | `graph:compression` | delta-varint connection codec |
26
+ * | `hnsw` | **Adaptive DiskANN** (`NativeDiskAnnWrapper`) — the vector index. The provider key is brainy's historical name; cor's implementation is DiskANN |
27
+ * | `diskann` | Same `NativeDiskAnnWrapper` under brainy's explicit DiskANN key (for callers that set `config.index.type='diskann'`) |
28
+ * | `cache` | Native eviction engine (`NativeUnifiedCacheWrapper`) |
29
+ * | `metadataIndex` | Native LSM-backed metadata index + column store |
30
+ * | `graphIndex` | Native graph adjacency (u64-keyed LSM trees) |
31
+ * | `embeddings` | Candle ML (CPU/CUDA/Metal) |
32
+ * | `embedBatch` | Single-forward-pass batch embeddings |
33
+ * | `entityIdMapper` | mmap binary mapper or JSON fallback |
34
+ * | `roaring` | CRoaring bindings (Roaring32 + Roaring64) |
35
+ * | `msgpack` | Native encode/decode |
36
+ * | `aggregation` | Rust-accelerated incremental aggregation |
37
+ * | `sort:topK` | `O(N log K)` bounded-heap ranking |
38
+ *
39
+ * The legacy native HNSW implementation (cortex 2.x) and its
40
+ * companion mmap vector store + BVEC reader were removed in
41
+ * Piece F. **Adaptive DiskANN** covers the same workload range
42
+ * with a single code path (in-memory / hybrid / on-disk modes
43
+ * selected at brain-open time from observed memory).
44
+ */
45
+ import type { BrainyPlugin } from '@soulcraft/brainy/plugin';
46
+ declare const corPlugin: BrainyPlugin & {
47
+ brainyRange?: string;
48
+ };
49
+ export default corPlugin;
50
+ //# sourceMappingURL=plugin.d.ts.map
package/dist/plugin.js ADDED
@@ -0,0 +1,388 @@
1
+ /**
2
+ * @module plugin
3
+ * @description `@soulcraft/cor` Brainy plugin entry point.
4
+ *
5
+ * Implements the `BrainyPlugin` interface to register every native
6
+ * provider cor 3.0 ships. Brainy auto-detects this plugin during
7
+ * `init()` via dynamic import.
8
+ *
9
+ * ## Tier gating
10
+ *
11
+ * - **Free tier (no license key)**: nothing registered — brainy runs
12
+ * on its pure-JS defaults with zero acceleration.
13
+ * - **Pro / Enterprise / Internal**: every compute provider below
14
+ * wired in. Cor is a pure 1:1 accelerator — it registers ONLY
15
+ * the providers brainy currently looks up; native capabilities
16
+ * that don't yet have a brainy hook stay dormant in the cdylib.
17
+ *
18
+ * ## Cor 3.0 surface (Piece F, 2026-06-09)
19
+ *
20
+ * | Provider | Implementation |
21
+ * |-------------------|---------------------------------------------|
22
+ * | `distance` | SIMD-accelerated cosine |
23
+ * | `distance:sq8` | SQ8 quantized cosine (uint8) |
24
+ * | `distance:sq4` | SQ4 quantized cosine (packed nibbles) |
25
+ * | `graph:compression` | delta-varint connection codec |
26
+ * | `hnsw` | **Adaptive DiskANN** (`NativeDiskAnnWrapper`) — the vector index. The provider key is brainy's historical name; cor's implementation is DiskANN |
27
+ * | `diskann` | Same `NativeDiskAnnWrapper` under brainy's explicit DiskANN key (for callers that set `config.index.type='diskann'`) |
28
+ * | `cache` | Native eviction engine (`NativeUnifiedCacheWrapper`) |
29
+ * | `metadataIndex` | Native LSM-backed metadata index + column store |
30
+ * | `graphIndex` | Native graph adjacency (u64-keyed LSM trees) |
31
+ * | `embeddings` | Candle ML (CPU/CUDA/Metal) |
32
+ * | `embedBatch` | Single-forward-pass batch embeddings |
33
+ * | `entityIdMapper` | mmap binary mapper or JSON fallback |
34
+ * | `roaring` | CRoaring bindings (Roaring32 + Roaring64) |
35
+ * | `msgpack` | Native encode/decode |
36
+ * | `aggregation` | Rust-accelerated incremental aggregation |
37
+ * | `sort:topK` | `O(N log K)` bounded-heap ranking |
38
+ *
39
+ * The legacy native HNSW implementation (cortex 2.x) and its
40
+ * companion mmap vector store + BVEC reader were removed in
41
+ * Piece F. **Adaptive DiskANN** covers the same workload range
42
+ * with a single code path (in-memory / hybrid / on-disk modes
43
+ * selected at brain-open time from observed memory).
44
+ */
45
+ import { loadNativeModule, isNativeAvailable } from './native/index.js';
46
+ import { validateLicense, readLicenseToken, readConfig, isShortCode } from './license.js';
47
+ import { MigrationCoordinator } from './migration/MigrationCoordinator.js';
48
+ const PRICING_URL = 'https://soulcraft.com/pricing?focus=pro';
49
+ // `brainyRange` engages brainy 8.0's version-coupling gate (handoff LV.3): a
50
+ // brainy outside this range fails loud at init() instead of silently dropping to
51
+ // the JS engine. Typed via intersection until the devDependency moves to brainy
52
+ // 8.0 (whose `BrainyPlugin` declares the field); brainy reads the runtime
53
+ // property regardless of cor's compile-time type. `'vector'` provider key is
54
+ // registered below (the other half of the gate's contract).
55
+ const corPlugin = {
56
+ name: '@soulcraft/cor',
57
+ brainyRange: '>=8.0.0 <9.0.0',
58
+ async activate(context) {
59
+ // **Safety guard — Cor 3.0 production default.** Refuse to start if
60
+ // the storage root still contains cortex 2.x on-disk artifacts. The
61
+ // check is *deferred to the storage-receiving provider factories
62
+ // below*: brainy 8.0's `activate(context)` does not expose the
63
+ // brain's storage here (the context carries only `registerProvider`
64
+ // + `version`), so scanning it now would inspect `undefined` and
65
+ // silently pass — defeating the safety net. `guardLegacyLayoutOnce`
66
+ // is called at the top of the metadataIndex / graphIndex /
67
+ // entityIdMapper factories, which DO receive the real storage, and
68
+ // fires before any native engine opens files under the root. A loud
69
+ // "service won't start" failure is recoverable; letting cor 3.0
70
+ // auto-engagement run alongside 2.x remnants produces a
71
+ // half-migrated state that's harder to undo. Bypass via env
72
+ // `COR_LEGACY_LAYOUT_GUARD=skip` (used by the migration script).
73
+ const { guardLegacyLayoutOnce } = await import('./legacyLayoutGuard.js');
74
+ // **Piece 19 storage simplification.** Cor does not register
75
+ // a `storage:filesystem` provider — brainy's built-in
76
+ // `FileSystemStorage` (which since 7.25.0 ships the binary-blob
77
+ // primitives + multi-process locking cor used to layer on
78
+ // top) is the canonical storage adapter. That keeps the
79
+ // boundary between brainy and cor razor-sharp:
80
+ //
81
+ // - **Brainy** = data + filesystem storage + JS default
82
+ // implementations of every operation (MIT open source).
83
+ // - **Cor** = drop-in fast replacements for every compute
84
+ // hot path (proprietary, license-gated).
85
+ //
86
+ // Cor's compute providers (Adaptive DiskANN, metadata index,
87
+ // graph adjacency, embeddings, etc.) all require local file
88
+ // paths via `storage.getBinaryBlobPath` — i.e. filesystem
89
+ // storage. On a cloud adapter the compute providers fail at
90
+ // init with a clear error rather than silently degrading.
91
+ // Brainy continues to work unaccelerated on any adapter.
92
+ // Gate: native module must be available for compute acceleration
93
+ if (!isNativeAvailable()) {
94
+ return true;
95
+ }
96
+ // Gate: license tier determines compute access
97
+ const license = await validateLicense();
98
+ let useOfflineGrace = false;
99
+ if (license.tier === 'free') {
100
+ if (license.error) {
101
+ // 'native module unavailable' — defensive; isNativeAvailable() already gated above
102
+ console.warn(`[cor] ${license.error}`);
103
+ return true;
104
+ }
105
+ // Distinguish "no key configured" from "short code exchange failed at runtime".
106
+ // The CLI now writes JWTs directly (sc_cor_...), so short codes in .soulcraft.json
107
+ // only appear in old or manually-written files. Exchange at runtime is a fallback path.
108
+ //
109
+ // Resolve the RAW license value with the same env-then-file precedence
110
+ // readLicenseToken() uses (env var COR_LICENSE_KEY / legacy CORTEX_LICENSE_KEY
111
+ // wins over .soulcraft.json). We can't reuse readLicenseToken() directly here
112
+ // because it exchanges short codes into JWTs (or returns null on a failed
113
+ // exchange), erasing the short-code shape this branch needs to test. Reading
114
+ // the file alone would drop offline grace for an env-supplied short code on a
115
+ // network blip — the exact gap this fixes.
116
+ const envValue = (process.env.COR_LICENSE_KEY ?? process.env.CORTEX_LICENSE_KEY)?.trim();
117
+ let licenseValue;
118
+ if (envValue) {
119
+ licenseValue = envValue;
120
+ }
121
+ else {
122
+ const config = await readConfig();
123
+ // Dual-read during the cortex→cor rename: new `cor` key, legacy `cortex`.
124
+ licenseValue = config.cor ?? config.cortex;
125
+ }
126
+ if (!licenseValue) {
127
+ return true; // No license configured — free tier, no warning
128
+ }
129
+ if (isShortCode(licenseValue)) {
130
+ // Exchange failed. Check heartbeat cache: if the license was previously active,
131
+ // grant offline grace so a transient network issue doesn't break production.
132
+ const { readHeartbeatCache } = await import('./license/onlineValidator.js');
133
+ const cached = await readHeartbeatCache();
134
+ if (cached?.status === 'active') {
135
+ const lastCheck = new Date(cached.lastCheck).toLocaleDateString();
136
+ console.warn(`[cor] License server unreachable — offline mode (last verified: ${lastCheck}). ` +
137
+ `Ensure soulcraft.com is accessible for periodic renewal.`);
138
+ useOfflineGrace = true;
139
+ }
140
+ else {
141
+ console.warn(`[cor] License exchange failed — cannot verify activation code with soulcraft.com.\n` +
142
+ `[cor] Native compute acceleration disabled.\n` +
143
+ `[cor] Re-run: npx @soulcraft/cor activate <code> (on a machine with internet access)`);
144
+ return true;
145
+ }
146
+ }
147
+ else {
148
+ return true; // JWT present but resolved to free — valid state, no warning
149
+ }
150
+ }
151
+ if (!useOfflineGrace) {
152
+ // Invalid key (bad signature, wrong product, expired, etc.)
153
+ if (!license.valid) {
154
+ if (license.error) {
155
+ console.warn(`[cor] ${license.error}. ` +
156
+ `Get a valid license at ${PRICING_URL}`);
157
+ }
158
+ return true;
159
+ }
160
+ // Check cached heartbeat state BEFORE registering compute providers.
161
+ // This catches an expired grace period from a previous run without a network call.
162
+ const { readHeartbeatCache, isGracePeriodExpired } = await import('./license/onlineValidator.js');
163
+ const cachedState = await readHeartbeatCache();
164
+ if (cachedState?.gracePeriodStart && isGracePeriodExpired(cachedState.gracePeriodStart)) {
165
+ console.warn('[cor] License lapsed. Compute acceleration disabled. Renew at soulcraft.com/account');
166
+ return true;
167
+ }
168
+ }
169
+ // Pro / Enterprise / Internal: register ALL native compute providers
170
+ const native = loadNativeModule();
171
+ // Distance: SIMD-accelerated cosine.
172
+ context.registerProvider('distance', native.cosineDistance);
173
+ // Quantized distance: SQ8 cosine on uint8 arrays (no
174
+ // dequantization). Used by brainy's SQ8 rerank path.
175
+ context.registerProvider('distance:sq8', native.cosineDistanceSq8);
176
+ // Quantized distance: SQ4 cosine on packed nibbles (2 values
177
+ // per byte). Used by brainy 7.28.0+ when
178
+ // `config.hnsw.quantization.bits === 4`. Byte-for-byte
179
+ // identical to brainy's pure-JS `distanceSQ4Js`;
180
+ // cross-language parity is asserted by brainy's test suite.
181
+ context.registerProvider('distance:sq4', native.cosineDistanceSq4);
182
+ // Graph connection compression: delta-varint encoded
183
+ // connection lists. Brainy uses this on the JS HNSW path it
184
+ // still owns for the standalone open-core deployment shape;
185
+ // cor provides the native codec.
186
+ context.registerProvider('graph:compression', {
187
+ encode: native.encodeConnections,
188
+ decode: native.decodeConnections,
189
+ });
190
+ // Metadata index: Native Rust query/mutation engine.
191
+ // Imported + captured BEFORE the vector factory so the DiskANN
192
+ // wrapper's lazy mapperResolver can close over `metadataIndexInstance`
193
+ // (the canonical entity-id mapper). The capture is also handed to the
194
+ // graphIndex factory below — the SAME mapper brainy resolves verb
195
+ // endpoints through at write time (`metadataIndex.getIdMapper().getOrAssign`);
196
+ // restored edges (#68) and DiskANN slot↔int resolution (#72) MUST use
197
+ // THIS one mapper. The resolver is lazy, so factory-call order between
198
+ // the providers doesn't matter.
199
+ const { MetadataIndexManager: NativeMetadataIndex } = await import('./utils/NativeMetadataIndex.js');
200
+ let metadataIndexInstance;
201
+ // **Adaptive DiskANN** — the sole vector index in cor 3.0.
202
+ // Registered against brainy 8.0's canonical `'vector'` provider
203
+ // key (algorithm-neutral; matches `VectorIndexProvider`). The
204
+ // wrapper self-selects operating mode (in-memory / hybrid /
205
+ // on-disk) from observed memory pressure per Piece I — no
206
+ // user-tunable algorithm choice. #72: the wrapper resolves slot↔uuid
207
+ // through the off-heap mmap slotmaps + the canonical mapper, so it is
208
+ // wired with the SAME lazy `getIdMapper()` resolver as the graph index.
209
+ const { NativeDiskAnnWrapper } = await import('./hnsw/NativeDiskAnnWrapper.js');
210
+ let vectorInstance;
211
+ const diskAnnFactory = (config, distanceFn, options) => {
212
+ // Capture the constructed wrapper so the #18 migration coordinator can reach
213
+ // the vector provider (brainy calls this factory once for the 'vector' key).
214
+ vectorInstance = new NativeDiskAnnWrapper(config, distanceFn, {
215
+ ...options,
216
+ mapperResolver: () => metadataIndexInstance?.getIdMapper(),
217
+ migrationCoordinator: getMigrationCoordinator,
218
+ });
219
+ return vectorInstance;
220
+ };
221
+ context.registerProvider('vector', diskAnnFactory);
222
+ // Cache: Native Rust eviction engine with JS data storage
223
+ const { NativeUnifiedCacheWrapper } = await import('./utils/NativeUnifiedCache.js');
224
+ context.registerProvider('cache', new NativeUnifiedCacheWrapper());
225
+ context.registerProvider('metadataIndex', (storage) => {
226
+ guardLegacyLayoutOnce(storage);
227
+ // The metadata index owns the #18 migration trigger: on a large stale brain
228
+ // its init() calls coordinator.start(). Create/resolve the one coordinator for
229
+ // this brain here (the context has no storage; the factories do).
230
+ ensureMigrationCoordinator(storage);
231
+ metadataIndexInstance = new NativeMetadataIndex(storage, {}, getMigrationCoordinator);
232
+ return metadataIndexInstance;
233
+ });
234
+ // Graph adjacency: Native 4 LSM-trees with verb tracking
235
+ const { GraphAdjacencyIndex: NativeGraphAdjacencyIndex } = await import('./graph/NativeGraphAdjacencyIndex.js');
236
+ // **Phase B graph acceleration (ADR-006) — self-wire.** brainy 8.0's
237
+ // `activate(context)` has no storage and its provider factories are
238
+ // called with storage only (not the constructed graphIndex), while the
239
+ // `graphAcceleration` value is feature-detected RAW (the factory is
240
+ // never invoked). So we register the adapter here, bound to a resolver
241
+ // the graphIndex factory fills once it builds the native engine — the
242
+ // adapter wraps that SAME native handle (never a second index). Until
243
+ // the engine is built + loaded, the adapter reports `isInitialized:
244
+ // false` and brainy keeps serving graph ops from TS.
245
+ let graphEngine;
246
+ // **#18 migration lock (coordinator).** One per brain, created on the first
247
+ // storage-receiving factory call (memoized) and shared by all three derived-
248
+ // index providers via the SAME lazy `() => migrationCoordinator` getter so
249
+ // factory-call order doesn't matter. It drives the blocking 7.x→8.0 upgrade
250
+ // (rebuild all 3 indexes from canonical under a lock brainy holds reads+writes
251
+ // behind) and answers the feature-detected isMigrating / migrationStatus
252
+ // methods each provider delegates to it.
253
+ let migrationCoordinator;
254
+ const getMigrationCoordinator = () => migrationCoordinator;
255
+ const ensureMigrationCoordinator = (storage) => {
256
+ if (!migrationCoordinator) {
257
+ migrationCoordinator = new MigrationCoordinator(storage, {
258
+ metadata: () => metadataIndexInstance,
259
+ vector: () => vectorInstance,
260
+ graph: () => graphEngine,
261
+ });
262
+ }
263
+ return migrationCoordinator;
264
+ };
265
+ context.registerProvider('graphIndex', (storage) => {
266
+ guardLegacyLayoutOnce(storage);
267
+ ensureMigrationCoordinator(storage);
268
+ // Pass a lazy resolver to the metadata index's entity-id mapper so
269
+ // graphIndex.rebuild() (restore path, #68) resolves verb endpoints
270
+ // through the SAME mapper brainy assigns ints with at write time.
271
+ graphEngine = new NativeGraphAdjacencyIndex(storage, {}, () => metadataIndexInstance?.getIdMapper(), getMigrationCoordinator);
272
+ return graphEngine;
273
+ });
274
+ const { GraphAccelerationAdapter } = await import('./graph/GraphAccelerationAdapter.js');
275
+ context.registerProvider('graphAcceleration', new GraphAccelerationAdapter(() => graphEngine));
276
+ // Embeddings: Candle ML native engine — initialized eagerly so the 88MB model
277
+ // is loaded at startup, not lazily on first embed call. This eliminates the
278
+ // ~883ms delay on the first embedding request (e.g. during onboarding seeding).
279
+ const { NativeEmbeddingEngine } = await import('./native/NativeEmbeddingEngine.js');
280
+ const engine = NativeEmbeddingEngine.getInstance();
281
+ if (!engine.isInitialized()) {
282
+ await engine.initialize();
283
+ }
284
+ context.registerProvider('embeddings', async (text) => {
285
+ if (Array.isArray(text)) {
286
+ return engine.embedBatch(text);
287
+ }
288
+ return engine.embed(text);
289
+ });
290
+ // Batch embeddings: single Rust forward pass for multiple texts
291
+ context.registerProvider('embedBatch', async (texts) => {
292
+ return engine.embedBatch(texts);
293
+ });
294
+ // Entity ID mapper: dispatch on storage capability.
295
+ //
296
+ // • Filesystem-backed storage (exposes `getBinaryBlobPath`) →
297
+ // the cor 3.0 mmap-backed binary mapper (billion-scale,
298
+ // constant-RAM, crash-safe).
299
+ // • Cloud / non-path storage → the JSON-persisted mapper.
300
+ //
301
+ // Both implement the same brainy `EntityIdMapperProvider` contract;
302
+ // the choice is transparent to brainy.
303
+ //
304
+ // This is a single dispatch, not a fallback chain. Either the
305
+ // storage has a local path (binary) or it does not (JSON). A
306
+ // failure constructing the binary mapper on a path-capable storage
307
+ // is a real bug and surfaces as an init error rather than silently
308
+ // degrading to JSON (which would mask corruption / config issues
309
+ // and quietly break the billion-scale guarantee for that node).
310
+ const { NativeEntityIdMapperWrapper } = await import('./utils/nativeEntityIdMapper.js');
311
+ const { NativeBinaryEntityIdMapperWrapper } = await import('./utils/nativeBinaryEntityIdMapper.js');
312
+ context.registerProvider('entityIdMapper', (storage) => {
313
+ guardLegacyLayoutOnce(storage);
314
+ if (typeof storage?.getBinaryBlobPath === 'function') {
315
+ return new NativeBinaryEntityIdMapperWrapper({ storage });
316
+ }
317
+ return new NativeEntityIdMapperWrapper({ storage });
318
+ });
319
+ // Roaring bitmaps: CRoaring bindings (binary-compatible with roaring-wasm)
320
+ const { RoaringBitmap32 } = await import('./native/NativeRoaringBitmap32.js');
321
+ context.registerProvider('roaring', RoaringBitmap32);
322
+ // Msgpack: Native encode/decode
323
+ context.registerProvider('msgpack', {
324
+ encode: native.msgpackEncode,
325
+ decode: native.msgpackDecode
326
+ });
327
+ // Aggregation: Rust-accelerated incremental aggregation.
328
+ // Precise MIN/MAX + exact percentile/distinctCount
329
+ // (value-multiset, never stale after deletes), HAVING,
330
+ // array-unnest groupBy, Rayon parallel rebuild. Registering
331
+ // the `'aggregation'` provider makes brainy's `AggregationIndex`
332
+ // delegate all metric computation to Rust.
333
+ const { NativeAggregationProvider } = await import('./aggregation/NativeAggregationEngine.js');
334
+ context.registerProvider('aggregation', new NativeAggregationProvider());
335
+ // Top-K result ranking: `O(N log K)` bounded-heap selection.
336
+ // Returns the indices of the best K scores in ranked order
337
+ // so brainy can rank a large candidate set (e.g. a 1M-result
338
+ // search with `limit=10`) without an `O(N log N)` full sort.
339
+ context.registerProvider('sort:topK', native.sortTopKScores);
340
+ // Resource Manager: adaptive memory budgeting for multi-instance deployments.
341
+ // Tracks active brainy instances, observes system resources (RAM, cgroups),
342
+ // and dynamically adjusts cache sizing. Zero-config — auto-detects VM size.
343
+ const { ResourceManager } = await import('./resource/ResourceManager.js');
344
+ const { getGlobalCache } = await import('@soulcraft/brainy/internals');
345
+ const resourceManager = ResourceManager.getInstance();
346
+ // Connect ResourceManager → UnifiedCache: when instance count changes,
347
+ // ResourceManager recalculates the cache budget and resizes dynamically.
348
+ const globalCache = getGlobalCache();
349
+ if (typeof globalCache.setMaxSize === 'function') {
350
+ resourceManager.setCacheResizeCallback((newSize) => {
351
+ globalCache.setMaxSize(newSize);
352
+ });
353
+ }
354
+ // ResourceManager runs internally (adaptive cache sizing, wired above) — it is
355
+ // not registered as a provider since brainy has no consumer for it.
356
+ resourceManager.startRebalancing();
357
+ // Background heartbeat with forceCheck — always checks Portal on startup.
358
+ // Updates the cache so the next startup sees current subscription state.
359
+ // Runs after providers are registered (non-blocking for the user).
360
+ // Skipped in offline grace mode — we have no JWT to send.
361
+ if (!useOfflineGrace) {
362
+ const token = await readLicenseToken();
363
+ if (token) {
364
+ import('./license/onlineValidator.js')
365
+ .then(({ performHeartbeat }) => performHeartbeat(token, { forceCheck: true }))
366
+ .then(result => {
367
+ if (result.degrade) {
368
+ const msg = result.warning ?? 'License lapsed. Compute acceleration disabled. Renew at soulcraft.com/account';
369
+ console.warn(`[cor] ${msg}`);
370
+ }
371
+ else if (result.warning) {
372
+ console.warn(`[cor] ${result.warning}`);
373
+ }
374
+ })
375
+ .catch(() => {
376
+ // Silently ignore heartbeat errors
377
+ });
378
+ }
379
+ }
380
+ return true;
381
+ },
382
+ async deactivate() {
383
+ // Native resources are cleaned up by the Rust drop() mechanism
384
+ // when the process exits. No explicit cleanup needed.
385
+ }
386
+ };
387
+ export default corPlugin;
388
+ //# sourceMappingURL=plugin.js.map