@dzhechkov/harness-core 0.8.33 → 0.8.34

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.
package/sbom.json CHANGED
@@ -25,7 +25,7 @@
25
25
  "hashes": [
26
26
  {
27
27
  "alg": "SHA-256",
28
- "content": "70cf5d858ca889a834345fe7c00f7312fc65477f5e5c3f6d2f4dd7d742ca2ed3"
28
+ "content": "7fb2af101753ac28e469a24a8f15789d0235d5749dd3a3cda42422d61ff13c0d"
29
29
  }
30
30
  ]
31
31
  },
@@ -75,7 +75,7 @@
75
75
  "hashes": [
76
76
  {
77
77
  "alg": "SHA-256",
78
- "content": "69023233508c656035c8a27b95690bcfddab535d25dffb85f2041c4bfbf77f64"
78
+ "content": "6e86eca1e1b3db58f83c5e60b3af2943cb97a7365eb9754825b3e2fcdde5fe22"
79
79
  }
80
80
  ]
81
81
  },
@@ -85,7 +85,7 @@
85
85
  "hashes": [
86
86
  {
87
87
  "alg": "SHA-256",
88
- "content": "965f21e2cb4c4f6ac8cf51b0238a64c3c44b0442ecc2ec198d67463bd7e76b31"
88
+ "content": "601500870a060848fd75912b8473b1d715ab4c97ea1d8c91db0711e0a0ebf352"
89
89
  }
90
90
  ]
91
91
  },
@@ -95,7 +95,7 @@
95
95
  "hashes": [
96
96
  {
97
97
  "alg": "SHA-256",
98
- "content": "2975c8ee201c4b6e7d78d0a7fc34e976d2d1c97692e6fce82c56417d90d397cd"
98
+ "content": "fdb88618197b66d9b107c50ac75b625e23a4498ddb20d13d8e9168d7e6aee790"
99
99
  }
100
100
  ]
101
101
  },
@@ -105,7 +105,7 @@
105
105
  "hashes": [
106
106
  {
107
107
  "alg": "SHA-256",
108
- "content": "866790c8dcb6614538513927c389231e3617ec5c883470e1e15c19d1f3b2128b"
108
+ "content": "8ada5fd59f070ece1436c97b0d4e96bc9067a2ab042a06637a4592ee9fcf74e9"
109
109
  }
110
110
  ]
111
111
  },
@@ -315,7 +315,7 @@
315
315
  "hashes": [
316
316
  {
317
317
  "alg": "SHA-256",
318
- "content": "a3b35c162ce1059ec52e66250f4d5eb40ea80031bc6ba211cf2c239125da2dab"
318
+ "content": "7d405581035820ac6e35fc3acf30685fb66f97120f4222d4389e81182cb234b6"
319
319
  }
320
320
  ]
321
321
  },
@@ -325,7 +325,7 @@
325
325
  "hashes": [
326
326
  {
327
327
  "alg": "SHA-256",
328
- "content": "a16afc919647db2ea568e29bf0e835df023a025716bf73e60ab5294300fee486"
328
+ "content": "1ec81dba7e182385ee9cebd1d4c41128915549797fb07bbff0cc540b7f72287a"
329
329
  }
330
330
  ]
331
331
  },
@@ -335,7 +335,7 @@
335
335
  "hashes": [
336
336
  {
337
337
  "alg": "SHA-256",
338
- "content": "604ff5b789bf969728c174c560a0b463d64307f0120699feb28ed839d0e42afa"
338
+ "content": "94a7c64d577a8134413cd508b37ec346cf729571b86b0d0cb55168d9a67f7a76"
339
339
  }
340
340
  ]
341
341
  },
@@ -345,7 +345,7 @@
345
345
  "hashes": [
346
346
  {
347
347
  "alg": "SHA-256",
348
- "content": "78b6f40ca672f6ea40ce4d29c9ae9baab74c74252400a5e05540272a612201b1"
348
+ "content": "cc1ed9820f186de277c75bbcffd102e651e34283a7728307d4c377ad7e207b7a"
349
349
  }
350
350
  ]
351
351
  },
@@ -2595,7 +2595,7 @@
2595
2595
  "hashes": [
2596
2596
  {
2597
2597
  "alg": "SHA-256",
2598
- "content": "9268dcea6b76bcc172de258f26b263384be72751ecd80bf695d30fa956ce3255"
2598
+ "content": "0ec8aabd62c19b421d56b9ddfc3a769ca88a6edad072e6b458a9ec0dce144847"
2599
2599
  }
2600
2600
  ]
2601
2601
  },
@@ -2605,7 +2605,7 @@
2605
2605
  "hashes": [
2606
2606
  {
2607
2607
  "alg": "SHA-256",
2608
- "content": "525593dc52d74876f41071fc906828b3b1807d5b8d1bf0e570589b8f5e23a6cd"
2608
+ "content": "d55811cc24161673964196697f78774b618ceff986f12d61233129af1309a06e"
2609
2609
  }
2610
2610
  ]
2611
2611
  },
@@ -2615,7 +2615,7 @@
2615
2615
  "hashes": [
2616
2616
  {
2617
2617
  "alg": "SHA-256",
2618
- "content": "645544ee8ebb51df85c94f1150134c76885678ac0c54dfaaacfaa38090549ee6"
2618
+ "content": "db5d3897a75a8b5f41e4d63fc2b89e1ba0ad59d81c9ec7409f4a4e4bcaef3ed2"
2619
2619
  }
2620
2620
  ]
2621
2621
  },
@@ -2625,7 +2625,7 @@
2625
2625
  "hashes": [
2626
2626
  {
2627
2627
  "alg": "SHA-256",
2628
- "content": "0a45a791953cdecc4fb0bff3d39ea158f1d204ba5c3507783affd94fc38c559a"
2628
+ "content": "7ed1c3d692bf9f60b3239b2ec714552c524139f98a666529c1c614c00b1928a2"
2629
2629
  }
2630
2630
  ]
2631
2631
  },
@@ -3725,7 +3725,7 @@
3725
3725
  "hashes": [
3726
3726
  {
3727
3727
  "alg": "SHA-256",
3728
- "content": "f147b33e2edd6766f4d8256f980315a1458f0408bb0683f5324ccee28e0b8223"
3728
+ "content": "5e21fd824b54842ab455e1c2b4d381d3ba81eaefb37ee525ab44b61f3e1a4719"
3729
3729
  }
3730
3730
  ]
3731
3731
  },
@@ -3735,7 +3735,7 @@
3735
3735
  "hashes": [
3736
3736
  {
3737
3737
  "alg": "SHA-256",
3738
- "content": "568d5ea2e70f3672deadf656384e0dedc8f02136e1aacfbff18b523ee0c90fa9"
3738
+ "content": "cb895bd26042f722c29594f1c5d0db6471146516745de6b366ed3b1a06af1906"
3739
3739
  }
3740
3740
  ]
3741
3741
  },
@@ -3745,7 +3745,7 @@
3745
3745
  "hashes": [
3746
3746
  {
3747
3747
  "alg": "SHA-256",
3748
- "content": "43e8044e64abc740d5db2486e149acdc943c58a046d9b0c94038e53c207fc0af"
3748
+ "content": "3d7103bd1f9c96aefe9ade44d53a321ae5c057171a6556b228350fc3faf74f33"
3749
3749
  }
3750
3750
  ]
3751
3751
  },
@@ -4195,7 +4195,7 @@
4195
4195
  "hashes": [
4196
4196
  {
4197
4197
  "alg": "SHA-256",
4198
- "content": "63e4bb439f1366114d21b9796489fec34308c34818bddeb6b69f590b8882c0fd"
4198
+ "content": "8e39c9f1d527ddaaa8b8655ee1e2fa0ee005926e25da8c3218cf0fb9cbed5502"
4199
4199
  }
4200
4200
  ]
4201
4201
  },
@@ -4205,7 +4205,7 @@
4205
4205
  "hashes": [
4206
4206
  {
4207
4207
  "alg": "SHA-256",
4208
- "content": "6c564150ddcb07ce2994c63764a0acb3d282bd702ed79dc906c886affc3e84e9"
4208
+ "content": "257237bac3a1d173113b4525ea19dbb4f7984a08ad017ebdd7af164ba6cc7cfe"
4209
4209
  }
4210
4210
  ]
4211
4211
  },
@@ -4215,7 +4215,7 @@
4215
4215
  "hashes": [
4216
4216
  {
4217
4217
  "alg": "SHA-256",
4218
- "content": "b99fca72e63868d9177052aefe47390e9f5e08ff6869d65299dc0286c8bdfd18"
4218
+ "content": "16ac3f704998f295ed42c112277482d6adfb5d26e4c8a4c89781d24b63118f6f"
4219
4219
  }
4220
4220
  ]
4221
4221
  },
@@ -4225,7 +4225,7 @@
4225
4225
  "hashes": [
4226
4226
  {
4227
4227
  "alg": "SHA-256",
4228
- "content": "504ecc5393016745aef5c60dfa9162a6531625a56b34ced46f4f8ee31d72bf11"
4228
+ "content": "8143d41cd1c706713fe6d9a742b71d9a28b3519a72072ca4683837ab54732d30"
4229
4229
  }
4230
4230
  ]
4231
4231
  },
@@ -4755,7 +4755,7 @@
4755
4755
  "hashes": [
4756
4756
  {
4757
4757
  "alg": "SHA-256",
4758
- "content": "cf5750b9c6d474c45cfd81b7cbb2f92a18b452fa1c069e4e3fbfc4dac06267d9"
4758
+ "content": "937161c359ffed77233d43ba2b5280cd8f34962baa1758daf8479805e23621ef"
4759
4759
  }
4760
4760
  ]
4761
4761
  },
@@ -4765,7 +4765,7 @@
4765
4765
  "hashes": [
4766
4766
  {
4767
4767
  "alg": "SHA-256",
4768
- "content": "6eaca079115921991149d68189ed8ef8c61be6efd12c426df8d091c1b39da5b9"
4768
+ "content": "6ce025a95be2b36246e6a8dbe3b324539e60d3f79febe1330071e51fced1282a"
4769
4769
  }
4770
4770
  ]
4771
4771
  },
@@ -4775,7 +4775,7 @@
4775
4775
  "hashes": [
4776
4776
  {
4777
4777
  "alg": "SHA-256",
4778
- "content": "627e5efa90298701d01bee346790647f5688dc0f10c4727b348298490c35d219"
4778
+ "content": "0030839d3dfaa43dabed352703255a7f6f0e11c8e3db01abaa4341fddb57e211"
4779
4779
  }
4780
4780
  ]
4781
4781
  },
@@ -4785,7 +4785,7 @@
4785
4785
  "hashes": [
4786
4786
  {
4787
4787
  "alg": "SHA-256",
4788
- "content": "a539f499cf28923856c6cb6f40417d67d662c6771b4df8fe4e7fe5ab9f2a7121"
4788
+ "content": "2f1cfa37c4f868859e6ea2b5aba4b896bd106e8ed1a9a8b5285b9ad30e52d896"
4789
4789
  }
4790
4790
  ]
4791
4791
  },
@@ -6635,7 +6635,7 @@
6635
6635
  "hashes": [
6636
6636
  {
6637
6637
  "alg": "SHA-256",
6638
- "content": "289cc4a73d023af16d44ab00caa4c1cad2cbe6bd6720b6eddf932ef37e200a5b"
6638
+ "content": "cdf68fa28b6a7e78d0381a5b2d23647ae812fee004e31b4c8c3893a897fd6f6f"
6639
6639
  }
6640
6640
  ]
6641
6641
  },
@@ -6645,7 +6645,7 @@
6645
6645
  "hashes": [
6646
6646
  {
6647
6647
  "alg": "SHA-256",
6648
- "content": "52e4813a1af157a58ea91b7787c44c09dfc68e44b0baee315182467913c4dc08"
6648
+ "content": "2943b848f7af427dcfecf801a778fe7eb2a6f899e395956aca5f45a9fcce3d79"
6649
6649
  }
6650
6650
  ]
6651
6651
  },
@@ -6655,7 +6655,7 @@
6655
6655
  "hashes": [
6656
6656
  {
6657
6657
  "alg": "SHA-256",
6658
- "content": "cf0d978a1e9bffb32a854d20a0a88a4daad7e852f12287db15ae1707c0db66a3"
6658
+ "content": "a48e13d799185bc95134a23cbe7d9ee91f9dcaf64c1c7c5faa4cf45a4cf94d08"
6659
6659
  }
6660
6660
  ]
6661
6661
  },
@@ -6665,7 +6665,7 @@
6665
6665
  "hashes": [
6666
6666
  {
6667
6667
  "alg": "SHA-256",
6668
- "content": "f8db2ecd2284f2d5af15049443aa295c56fa3d67a2240bb4f08b884f36cf41bd"
6668
+ "content": "9a74e49879f494f01aec757b4efe0f41245cf20cf1cc4e07123852f6939463cf"
6669
6669
  }
6670
6670
  ]
6671
6671
  },
@@ -6839,7 +6839,7 @@
6839
6839
  },
6840
6840
  {
6841
6841
  "name": "dz:canonical-json-sha256-v2",
6842
- "value": "a6f86350222413a151c6d4f73d9c80f4e2d3c21297000e2fe7b0708248d77724"
6842
+ "value": "26a1b1c5cd3d01ea854d9fb9ef126fe3cfd6580a52d0a1c7b60f4dffcc280d8d"
6843
6843
  }
6844
6844
  ]
6845
6845
  },
@@ -6859,7 +6859,7 @@
6859
6859
  "hashes": [
6860
6860
  {
6861
6861
  "alg": "SHA-256",
6862
- "content": "49c55278320cf79d50463374cb4bd98702381eefc61aa81cf3889f117857f7d0"
6862
+ "content": "f3b7a86fc7ec49fc7b47d69a6beb4ace4e193f9a4b63237b257a7cae1879d4f7"
6863
6863
  }
6864
6864
  ]
6865
6865
  },
@@ -6919,7 +6919,7 @@
6919
6919
  "hashes": [
6920
6920
  {
6921
6921
  "alg": "SHA-256",
6922
- "content": "15feafe9dedd298f2d8f7815d2a100cedaf4864223affb80f8e8c34317e4b0f6"
6922
+ "content": "d0bc07ff16397b8d0d6b26fd72a770553f421902b81e3d5e775e08b4db4710a3"
6923
6923
  }
6924
6924
  ]
6925
6925
  },
@@ -7499,7 +7499,7 @@
7499
7499
  "hashes": [
7500
7500
  {
7501
7501
  "alg": "SHA-256",
7502
- "content": "307f2d574fd2d7a0f2b8ebe7a36047f0c3d8cade6e8fdda9e10e26d344914912"
7502
+ "content": "a2ae53ebaa9993545153419f615db85f7a2d412f61deddb44780773e8ea52be2"
7503
7503
  }
7504
7504
  ]
7505
7505
  },
@@ -7789,7 +7789,7 @@
7789
7789
  "hashes": [
7790
7790
  {
7791
7791
  "alg": "SHA-256",
7792
- "content": "fd66a40569fd53cbf0d621643ace1e4f89777e9634bcda24a730e971dc240ccd"
7792
+ "content": "9f20a5a9c3e6ff41245612f74f04f62e719744fab2f97ee9d93fcdf4fa52668b"
7793
7793
  }
7794
7794
  ]
7795
7795
  },
@@ -7909,7 +7909,7 @@
7909
7909
  "hashes": [
7910
7910
  {
7911
7911
  "alg": "SHA-256",
7912
- "content": "2bd607ec044e2bca2a7336e10d69cee99db53e6f41b60bfa770711d756dd9116"
7912
+ "content": "5a7c2cffce4e62e4e859578b7014020670125e1ea68d4e04f2b1f6256c423b7a"
7913
7913
  }
7914
7914
  ]
7915
7915
  },
@@ -8049,7 +8049,7 @@
8049
8049
  "hashes": [
8050
8050
  {
8051
8051
  "alg": "SHA-256",
8052
- "content": "b7e248afaadc503642ef3b22eb86817e8ecb12744493c1780065de87772483a4"
8052
+ "content": "4e3390606a39f54b2a15db985a6e72a4f34c2ef59765c5124e1d64844d97447c"
8053
8053
  }
8054
8054
  ]
8055
8055
  },
@@ -8519,7 +8519,7 @@
8519
8519
  "hashes": [
8520
8520
  {
8521
8521
  "alg": "SHA-256",
8522
- "content": "f5b5187d2537f2d00c3f248676928d286e715e9984f67491aa1e02eb0f4b1b50"
8522
+ "content": "6086c8aabf98d69d9fc7d8b22d88dfbe1588ac1a4e2ddae66a3738e02dc638f2"
8523
8523
  }
8524
8524
  ]
8525
8525
  },
@@ -284,30 +284,43 @@ export interface AgentdbSearchResult {
284
284
 
285
285
  const DEPS_MISSING = 'agentdb/better-sqlite3 not installed in project (run: dz setup --memory agentdb)';
286
286
 
287
+ type Embedder = { embed: (t: string) => Promise<Float32Array> } | { error: string };
288
+
287
289
  /**
288
- * Resolve agentdb's `EmbeddingService` from the PROJECT (same dynamic-resolution discipline as
289
- * {@link indexPatternsToAgentdb}); every dz call site uses the same resolved model so query and row
290
- * vectors stay in the same space.
290
+ * `agentdb-embedder-cache` (feature): the transformers pipeline behind `EmbeddingService` is
291
+ * expensive to stand up (MEASURED 2026-09-14: 2-3.6s per `resolveAgentdbEmbedder` call — see
292
+ * `features/agentdb-embedder-cache/00_complexity_assessment.md`), yet the resolved model/dim never
293
+ * changes within one process. Keyed by `${agentdbDir}|${model}|${dim}` so a config/env change (a
294
+ * different `resolveEmbedModel` source) gets its own entry (FR-2) rather than reusing a stale
295
+ * pipeline. The PROMISE is cached, not the awaited result (FR-4): concurrent first callers for the
296
+ * same key join the same in-flight initialization instead of racing two pipelines. An `{error}`
297
+ * outcome (or a rejection) evicts its own entry so the next call retries cleanly (FR-3) — a failure
298
+ * must never "stick".
291
299
  */
292
- export async function resolveAgentdbEmbedder(
293
- projectRoot: string,
294
- ): Promise<{ embed: (t: string) => Promise<Float32Array> } | { error: string }> {
295
- let agentdbDir: string;
296
- try {
297
- const req = createRequire(join(projectRoot, 'package.json'));
298
- agentdbDir = dirname(req.resolve('agentdb'));
299
- } catch {
300
- return { error: DEPS_MISSING };
301
- }
300
+ const embedderCache = new Map<string, Promise<Embedder>>();
301
+ let embedderCacheInitializations = 0;
302
+
303
+ /** Test-only (and future warm-start) reset — callers (`vector-tier.ts`, `backlog.ts`) are unaffected. */
304
+ export function resetAgentdbEmbedderCache(): void {
305
+ embedderCache.clear();
306
+ embedderCacheInitializations = 0;
307
+ }
308
+
309
+ /** `entries` = cached keys right now — a SUCCESSFUL pipeline or an IN-FLIGHT initialization (the promise is
310
+ * cached before it settles, FR-4; a failed one is evicted, FR-3); `initializations` = pipelines actually
311
+ * started since the last reset. (Codex round-1, 2026-09-14: the earlier wording said "successful" only.) */
312
+ export function getAgentdbEmbedderCacheStats(): { entries: number; initializations: number } {
313
+ return { entries: embedderCache.size, initializations: embedderCacheInitializations };
314
+ }
315
+
316
+ async function initAgentdbEmbedder(agentdbDir: string, model: string, dim: number): Promise<Embedder> {
302
317
  try {
303
318
  const { EmbeddingService } = (await import(pathToFileURL(join(agentdbDir, 'controllers', 'EmbeddingService.js')).href)) as {
304
319
  EmbeddingService: new (o: object) => { initialize: () => Promise<void>; embed: (t: string) => Promise<Float32Array> };
305
320
  };
306
- const model = resolveEmbedModel(projectRoot);
307
- if ('error' in model) return { error: model.error };
308
321
  const emb = new EmbeddingService({
309
- model: model.model,
310
- dimension: model.dim,
322
+ model,
323
+ dimension: dim,
311
324
  provider: 'transformers',
312
325
  // agentdb >= 3.0.0-alpha.20 refuses UNREGISTERED models without an explicit role policy
313
326
  // (its built-in registry knows all-MiniLM-L6-v2 but not our multilingual variant — grounded
@@ -325,6 +338,41 @@ export async function resolveAgentdbEmbedder(
325
338
  }
326
339
  }
327
340
 
341
+ /**
342
+ * Resolve agentdb's `EmbeddingService` from the PROJECT (same dynamic-resolution discipline as
343
+ * {@link indexPatternsToAgentdb}); every dz call site uses the same resolved model so query and row
344
+ * vectors stay in the same space. Cached per process — see {@link embedderCache} above.
345
+ */
346
+ export async function resolveAgentdbEmbedder(projectRoot: string): Promise<Embedder> {
347
+ let agentdbDir: string;
348
+ try {
349
+ const req = createRequire(join(projectRoot, 'package.json'));
350
+ agentdbDir = dirname(req.resolve('agentdb'));
351
+ } catch {
352
+ return { error: DEPS_MISSING };
353
+ }
354
+ const model = resolveEmbedModel(projectRoot);
355
+ if ('error' in model) return { error: model.error };
356
+ const key = `${agentdbDir}|${model.model}|${model.dim}`;
357
+ const hit = embedderCache.get(key);
358
+ if (hit !== undefined) return hit;
359
+ embedderCacheInitializations += 1;
360
+ const promise = initAgentdbEmbedder(agentdbDir, model.model, model.dim);
361
+ embedderCache.set(key, promise);
362
+ // FR-3: an init failure must not stick — evict so the next call retries instead of replaying
363
+ // the same {error} forever. `.catch` here only guards a rejection that slips past
364
+ // `initAgentdbEmbedder`'s own try/catch; it never rethrows (this is bookkeeping, not the return path).
365
+ void promise.then(
366
+ (result) => {
367
+ if ('error' in result && embedderCache.get(key) === promise) embedderCache.delete(key);
368
+ },
369
+ () => {
370
+ if (embedderCache.get(key) === promise) embedderCache.delete(key);
371
+ },
372
+ );
373
+ return promise;
374
+ }
375
+
328
376
  /** `absent: true` = no store file yet — an EMPTY mirror is a state, not an error (backfill relies on this). */
329
377
  function openReadonly(projectRoot: string, dbPath?: string): { db: ReadonlyDb } | { absent: true } | { error: string } {
330
378
  const dbFile = resolveAgentdbPath(projectRoot, dbPath);