@avantf/dsh-mem 0.6.3 → 0.6.4

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.
@@ -115,6 +115,12 @@ export declare class ChunksDao {
115
115
  * This is what lets the shared repair flow read "what is stale" cheaply per slice instead of
116
116
  * re-scanning and hashing the corpus (`corpusState` reads every text; a batched migration must
117
117
  * not).
118
+ *
119
+ * The JS rule itself is `store/vector_space.ts` (`classifyVectorSpace` / `countVectorSpace`), and
120
+ * this projection is bound to it by the cross assertions in
121
+ * `test/knowledge_vector_migration.spec.ts` (the startup warning's count, the health count and the
122
+ * migration's `remaining` all have to be the same number). NOTHING here changes when the JS rule
123
+ * changes: the mirror is checked, not shared.
118
124
  */
119
125
  vectorSpaceCounts(space: string, expectedBytes: number): {
120
126
  stale: number;
@@ -8,10 +8,28 @@
8
8
  * The SQL lives here like every other aggregate. The store decides WHICH source a write carries
9
9
  * (and refuses to invent one when the caller gave none); the DAO only records and reads rows.
10
10
  */
11
+ import type { FactSourceView } from '../../../mem-contract/index.js';
11
12
  import type { Db } from '../port.js';
12
- /** The closed `kind` vocabulary, spelled once so the store and the tests share it. */
13
+ /**
14
+ * The kind axis is the CONTRACT's, not a second list: `FactSourceView['kind']` is what `admin detail`
15
+ * renders and what the writer below records, so deriving the type from it is what makes "the closed
16
+ * vocabulary" one thing. (Before, the array here and the union in `types.ts` were two independent
17
+ * spellings that happened to agree.)
18
+ */
19
+ export type FactSourceKind = FactSourceView['kind'];
20
+ /**
21
+ * The closed `kind` vocabulary, spelled once so the store and the tests share it.
22
+ *
23
+ * The `satisfies` pins every member to the contract's union; the `Exclude` below pins the other
24
+ * direction, so a kind the contract ADDS fails to compile here instead of silently never being
25
+ * recorded.
26
+ */
13
27
  export declare const FACT_SOURCE_KINDS: readonly ["session", "kb_doc", "tool", "manual"];
14
- export type FactSourceKind = (typeof FACT_SOURCE_KINDS)[number];
28
+ /**
29
+ * The FALLBACK kind: a `source_ref` without a recognized `kind:` prefix is `manual` with the
30
+ * reference kept VERBATIM (the tool contract says so, and "no shape guessing" is the point).
31
+ */
32
+ export declare const FACT_SOURCE_FALLBACK_KIND: "manual";
15
33
  /** One provenance row as the read surfaces render it. */
16
34
  export interface FactSource {
17
35
  kind: FactSourceKind;
@@ -21,10 +39,14 @@ export interface FactSource {
21
39
  * Derive `(kind, ref)` from the single `source_ref` the write face accepts.
22
40
  *
23
41
  * The tool takes ONE string (the plan adds no second parameter), so the kind axis is spelled by a
24
- * `kind:` prefix — `session:…` / `kb_doc:…` / `tool:…` — and anything else is `manual` with the
25
- * reference kept VERBATIM. No shape guessing: a bare `domain:source:title` becomes a `manual`
26
- * source whose ref is exactly what the caller wrote, which is strictly more honest than inventing
27
- * a category from how the string looks.
42
+ * `kind:` prefix — `session:…` / `kb_doc:…` / `tool:…` — and anything else, INCLUDING the fallback
43
+ * kind's own name, is `manual` with the reference kept VERBATIM. No shape guessing: a bare
44
+ * `domain:source:title` becomes a `manual` source whose ref is exactly what the caller wrote, which
45
+ * is strictly more honest than inventing a category from how the string looks.
46
+ *
47
+ * The prefix table comes from {@link FACT_SOURCE_KINDS} (see {@link FACT_SOURCE_PREFIX_KINDS}) rather
48
+ * than from a hand-written alternation, which is what keeps the recognized set and the recorded set
49
+ * from being two lists.
28
50
  */
29
51
  export declare function classifySourceRef(sourceRef: string): {
30
52
  kind: FactSourceKind;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The two page/result defaults the engine falls back to when neither the caller nor the config says
3
+ * anything — spelled ONCE, because each of them used to be written in two or three places.
4
+ *
5
+ * They are the ENGINE's consumption points of numbers the CONTRACT documents:
6
+ *
7
+ * - `DEFAULT_SEARCH_LIMIT` — `query`'s own input schema carries `.default(10)`
8
+ * (`contract/src/tools.ts`), and the recall actions' descriptions say "默认 10"; the recall union
9
+ * itself is `.optional()`, so the engine is what applies it. It reaches `hybridSearch` (a
10
+ * non-finite limit) and the cross-store router.
11
+ * - `DEFAULT_LIST_LIMIT` — the documented page for `admin list` and `kb_list` ("默认 50" /
12
+ * "缺省 50", same file).
13
+ *
14
+ * The cross-layer equation is pinned by `test/hybrid.spec.ts` against the contract's parsed schema,
15
+ * so a contract default moving and this constant not moving is a red test rather than a silent
16
+ * off-by-page behaviour. (These live here rather than in the contract because `@avantf/mem-contract`
17
+ * is consumed as built output: a constant added there is only visible to this engine after the
18
+ * contract is rebuilt, which a source-only change may not assume.)
19
+ *
20
+ * @module defaults
21
+ */
22
+ /** Page of a recall/query result when the caller gave no usable `limit`. */
23
+ export declare const DEFAULT_SEARCH_LIMIT = 10;
24
+ /** Page of a listing surface (`admin list`, `kb_list`) when the caller gave no `limit`. */
25
+ export declare const DEFAULT_LIST_LIMIT = 50;
@@ -16,10 +16,12 @@
16
16
  import type { KbAddRequest, ToolEnvelope, ToolSpec } from '../mem-contract/index.js';
17
17
  import type { AvantfRuntime } from './runtime.js';
18
18
  /**
19
- * The default page for a model-facing `kb_list`.
19
+ * The default page for a model-facing `kb_list` — the SAME page the operator's `admin list` uses.
20
20
  *
21
21
  * Without one, `kb_list` on a large library read and parsed EVERY managed file (resolving a path
22
- * needs the file's frontmatter to detect collisions) to answer a question nobody asked in full.
22
+ * needs the file's frontmatter to detect collisions) to answer a question nobody asked in full. The
23
+ * two surfaces were separate literals; the contract documents both as 50, so they are one constant
24
+ * (`src/defaults.ts`).
23
25
  */
24
26
  export declare const KB_LIST_DEFAULT_LIMIT = 50;
25
27
  /**
@@ -55,22 +55,6 @@ export interface WarmOptions {
55
55
  * path keeps it, because there the caller only sees this logger.
56
56
  */
57
57
  export declare function warmModels(rt: AvantfRuntime, options?: WarmOptions, reportFinal?: boolean): Promise<boolean>;
58
- /**
59
- * Warm ONLY the embedding model: load it from `semantic.cache_dir` and mark the engine ready.
60
- *
61
- * Split out of {@link warmModels} for the plugin's envinit path. There the framework fetches the
62
- * model in the BACKGROUND, so the warm has to wait for the item to settle instead of running at
63
- * mount — and the runtime's own constructor warm is deferred for exactly that reason
64
- * (`RuntimeOptions.managedRoots` → `deferWarm`), which is what stops it racing the install and
65
- * leaving a second copy behind. While the item is unsettled NOTHING warms; this function is the
66
- * explicit "files are there now, look" step, and it still runs when the item skipped/failed so
67
- * `semantic.auto_download` can decide between the runtime's own fetch and degradation.
68
- *
69
- * @param rt - the runtime whose memory store owns the semantic backend.
70
- * @param reportFinal - log the one-line verdict (default `true`).
71
- * @returns whether the semantic path is available.
72
- */
73
- export declare function warmSemantic(rt: AvantfRuntime, reportFinal?: boolean): Promise<boolean>;
74
58
  /**
75
59
  * Wait out the startup gate — the host readiness signal (bounded by {@link WAIT_FOR_HOST_MS}) and,
76
60
  * when asked, one quiet turn of the event loop.
@@ -88,18 +72,6 @@ export declare function warmSemantic(rt: AvantfRuntime, reportFinal?: boolean):
88
72
  * @returns how long the idle gate waited (ms), or `0` when it was not requested.
89
73
  */
90
74
  export declare function awaitStartupGate(options?: WarmOptions): Promise<number>;
91
- /**
92
- * Warm ONLY the tokenizer, after the host-readiness signal and (when asked) an idle event loop.
93
- *
94
- * nodejieba loads its dictionary lazily on the FIRST `tag()` (measured ~950 ms, after which a call
95
- * is 0.1 ms), so without this the first write/query of a session pays it while the user waits. Its
96
- * cost belongs to startup, and an unavailable jieba is worth saying out loud — entity extraction
97
- * silently degrades to the regex fallback (weaker entity/jaccard legs).
98
- *
99
- * @param rt - the runtime whose logger reports the outcome.
100
- * @param options - the host-readiness signal and the idle gate (see {@link WarmOptions}).
101
- */
102
- export declare function warmTokenizer(rt: AvantfRuntime, options?: WarmOptions): Promise<void>;
103
75
  /**
104
76
  * Non-blocking embedding warm, for a caller that knows the model files are already on disk.
105
77
  *
@@ -160,48 +132,7 @@ export interface ProvisionSweepResult {
160
132
  * @returns whether the sweep ran or was skipped for incompatibility.
161
133
  */
162
134
  export declare function provisionToolchainAsync(rt: AvantfRuntime, options?: ProvisionSweepOptions): Promise<ProvisionSweepResult>;
163
- /** The artifact id, used in the startup log and in the model artifact's errors. */
164
- export declare const MODEL_ARTIFACT_ID = "model";
165
135
  /** The environment a model-artifact call runs under: the runtime that owns the model cache. */
166
136
  export interface ModelArtifactEnv {
167
137
  runtime: AvantfRuntime;
168
138
  }
169
- /** The slice of an artifact call this module needs (`@avantf/mem-provision`'s InstallContext). */
170
- interface ModelInstallContext {
171
- logger: {
172
- info(message: string): void;
173
- warn(message: string): void;
174
- error(message: string): void;
175
- };
176
- artifactEnv?: unknown;
177
- config: {
178
- auto_install: boolean;
179
- };
180
- }
181
- /**
182
- * The embedding model (plus the nodejieba tokenizer it shares its warm-up budget with) as an
183
- * ARTIFACT, so the startup sweep in `@avantf/mem-provision` is the only initialization path.
184
- *
185
- * It used to be a parallel model warm-up call beside the tools sweep, which meant two
186
- * startup mechanisms with two logging vocabularies and no single place that answered "is this host
187
- * fully provisioned?". The model has no pinned version and no managed directory of its own ON THIS
188
- * (the flat `<repo>/<file>` layout the transformers.js cache reads), so it
189
- * declares neither; its `isPresent` is `false` because "is the model warm?" is not a question that
190
- * can be answered without attempting the warm-up, and the warm-up is cheap when the cache is
191
- * already there (measured ~1.2 s, in the background). The DSH plugin uses this sweep only when the
192
- * family framework is unavailable — with the framework up, `mem:model` owns the model root instead
193
- * and this artifact is not registered.
194
- */
195
- export declare const modelArtifact: {
196
- id: string;
197
- title: string;
198
- verb: string;
199
- isPresent(): Promise<boolean>;
200
- install(ctx: ModelInstallContext): Promise<void>;
201
- verify(ctx: {
202
- logger: ModelInstallContext["logger"];
203
- }): Promise<void>;
204
- };
205
- /** Register the model artifact once per process (idempotent for a test that mounts twice). */
206
- export declare function registerModelArtifact(): void;
207
- export {};
@@ -26,8 +26,6 @@
26
26
  import { type Config, type FloorProfile, type RecallResult, type RetrievalFloorDrops, type RetrievalFloors } from '../../mem-contract/index.js';
27
27
  import { type BudgetInput, type Hit, type SemanticBackend } from '../../mem-retrieval/index.js';
28
28
  import { type FloorLeg } from './floors.js';
29
- /** The `limit` a caller gets when it passes nothing usable. */
30
- export declare const DEFAULT_SEARCH_LIMIT = 10;
31
29
  /**
32
30
  * A retrieval input the CALLER got wrong, as opposed to a backend that failed at runtime.
33
31
  *
@@ -39,8 +37,6 @@ export declare const DEFAULT_SEARCH_LIMIT = 10;
39
37
  */
40
38
  export declare class RetrievalInputError extends Error {
41
39
  }
42
- /** …and the over-fetch factor when the config does not set one (matches the contract default). */
43
- export declare const DEFAULT_OVER_FETCH_FACTOR = 5;
44
40
  /** The three weights a `RecallResult` reports. */
45
41
  export type RetrievalWeights = RecallResult['weights'];
46
42
  /** One retrieval leg's contribution to the fusion. */
@@ -0,0 +1,60 @@
1
+ import type { StaleVectorCounts } from './common.js';
2
+ /** What one persisted vector IS, in the current space. */
3
+ export type VectorSpaceVerdict = 'current' | 'stale' | 'space_stale';
4
+ /**
5
+ * A persisted vector's width, in whichever shape the CALLER already has it — the discriminant is the
6
+ * shape, never the truth:
7
+ *
8
+ * - `blob` — the raw BLOB (`Uint8Array`), for a caller that has read the bytes;
9
+ * - `byteLength` — a projected `length(semantic_vector)`, for a caller that must not read them;
10
+ * - `decoded` — an already decoded `Float32Array`, for a caller that had to decode anyway.
11
+ *
12
+ * All three answer the same question (`width === dim`), which is the point: the caller with the
13
+ * cheapest possible evidence is not forced to re-read the row in another shape. A `null`/`undefined`
14
+ * width is "no usable bytes" and classifies as `stale`, like a wrong one.
15
+ */
16
+ export type PersistedVectorWidth = {
17
+ readonly source: 'blob';
18
+ readonly vec: Uint8Array | null | undefined;
19
+ } | {
20
+ readonly source: 'byteLength';
21
+ readonly byteLength: number | null | undefined;
22
+ } | {
23
+ readonly source: 'decoded';
24
+ readonly vec: Float32Array | null | undefined;
25
+ };
26
+ /** One width probe plus the space RECORDED beside it (the second element of the rule). */
27
+ export type VectorSpaceProbe = PersistedVectorWidth & {
28
+ /** `facts.embedding_model` / `doc_chunks.embedding_model` of the same row; `null` = unrecorded. */
29
+ readonly embeddingModel: string | null | undefined;
30
+ };
31
+ /** The space the store writes into RIGHT NOW. */
32
+ export interface VectorSpaceIdentity {
33
+ /** The representation fingerprint (`vectorSpaceOf`). */
34
+ readonly space: string;
35
+ /** The width the store writes now, in floats. */
36
+ readonly dim: number;
37
+ }
38
+ /** One row's classification. */
39
+ export interface VectorSpaceClassification {
40
+ readonly verdict: VectorSpaceVerdict;
41
+ /** Of a `space_stale` verdict: the recorded id predates the representation fingerprint. */
42
+ readonly legacy: boolean;
43
+ }
44
+ /**
45
+ * Classify ONE persisted vector. Pure: no store, no database, no logging — a caller that disagrees
46
+ * with the result has to disagree with the rule, not with a copy of it.
47
+ *
48
+ * A caller-supplied vector is trusted to come from this backend, but its DIMENSION is still checked
49
+ * — the same asymmetry `legs.ts` applies to a caller-supplied `queryVector`: provenance is the
50
+ * caller's to assert, width is cheap and decides whether the bytes can be compared at all.
51
+ */
52
+ export declare function classifyVectorSpace(probe: VectorSpaceProbe, identity: VectorSpaceIdentity): VectorSpaceClassification;
53
+ /**
54
+ * {@link classifyVectorSpace} over a corpus: the `{ stale, space_stale, legacy }` triple the warning
55
+ * and the `/mem` status surface report, counted by the same rule that classified each row.
56
+ *
57
+ * `legacy` counts only rows already counted in `space_stale` (`reportStaleVectors` clamps it there
58
+ * too) — it is a REASON split, never a fourth bucket.
59
+ */
60
+ export declare function countVectorSpace(probes: readonly VectorSpaceProbe[], identity: VectorSpaceIdentity): StaleVectorCounts;
package/lib/index.js CHANGED
@@ -3777,8 +3777,19 @@ const modelArtifact = {
3777
3777
  };
3778
3778
  /** Register the model artifact once per process (idempotent for a test that mounts twice). */
3779
3779
  function registerModelArtifact() {
3780
- if (!hasArtifact("model")) registerArtifact(modelArtifact);
3780
+ if (!hasArtifact(MODEL_ARTIFACT_ID)) registerArtifact(modelArtifact);
3781
3781
  }
3782
+ //#endregion
3783
+ //#region ../core/lib/dispatch.js
3784
+ /**
3785
+ * The default page for a model-facing `kb_list` — the SAME page the operator's `admin list` uses.
3786
+ *
3787
+ * Without one, `kb_list` on a large library read and parsed EVERY managed file (resolving a path
3788
+ * needs the file's frontmatter to detect collisions) to answer a question nobody asked in full. The
3789
+ * two surfaces were separate literals; the contract documents both as 50, so they are one constant
3790
+ * (`src/defaults.ts`).
3791
+ */
3792
+ const KB_LIST_DEFAULT_LIMIT = 50;
3782
3793
  /** A document view with the managed file's path — what makes "edit it yourself" actionable. */
3783
3794
  function withFilePath(rt, doc) {
3784
3795
  return {
@@ -3821,7 +3832,7 @@ const DISPATCH = {
3821
3832
  const detail = rt.knowledge.detail(data.doc_id);
3822
3833
  return detail === null ? { error: `文档不存在:doc_id=${String(data.doc_id)}` } : withFilePath(rt, detail);
3823
3834
  }
3824
- return rt.knowledge.list(data.domain, data.source, data.limit ?? 50, data.offset).map((doc) => withFilePath(rt, doc));
3835
+ return rt.knowledge.list(data.domain, data.source, data.limit ?? KB_LIST_DEFAULT_LIMIT, data.offset).map((doc) => withFilePath(rt, doc));
3825
3836
  }),
3826
3837
  kb_remove: ((rt, data) => rt.kb({
3827
3838
  action: "remove",
@@ -7428,6 +7439,33 @@ function mergeFloorDrops(...parts) {
7428
7439
  function totalFloorDrops(drops) {
7429
7440
  return drops.semantic + drops.fts + drops.jaccard + drops.hrr;
7430
7441
  }
7442
+ //#endregion
7443
+ //#region ../core/lib/store/hybrid.js
7444
+ /**
7445
+ * The retrieval orchestration BOTH stores run.
7446
+ *
7447
+ * `MemoryStore.search` and `KnowledgeStore.search` used to carry parallel copies of this flow
7448
+ * (~80 lines each: limit normalization → weights → over-fetch → leg cap → fuse → live filter →
7449
+ * slice → output budget → health event). The legs themselves are legitimately store-specific —
7450
+ * different tables, different filters (`category` vs `domain`/`source`), and only memory has the
7451
+ * HRR probe — but the ORCHESTRATION is one algorithm, and two copies of it drifted:
7452
+ *
7453
+ * - the `NaN` limit guard existed only in memory, so a non-finite limit reached knowledge's SQL
7454
+ * `LIMIT` and took the whole cross-store query down with it (`Promise.all` has no per-leg catch);
7455
+ * - `retriever.over_fetch_factor` was read only by memory, while knowledge hardcoded `limit * 3`,
7456
+ * so one config knob silently meant two different things;
7457
+ * - `recordLegCapped()` was called only by memory, so a capped knowledge leg was unobservable —
7458
+ * exactly the blindness DESIGN §20.17 says the counter exists to remove.
7459
+ *
7460
+ * Fixing those one at a time would leave the next drift a matter of when. The stores now supply
7461
+ * their legs and their hit mapping; everything that can drift lives here once.
7462
+ *
7463
+ * A leg that THROWS is isolated: it contributes nothing, the query still answers from the others,
7464
+ * and the failure is logged. The read path used to have no per-leg catch at all (the write path
7465
+ * did), so an ONNX error at inference cost the caller the FTS and entity legs too.
7466
+ *
7467
+ * @module store/hybrid
7468
+ */
7431
7469
  /**
7432
7470
  * A retrieval input the CALLER got wrong, as opposed to a backend that failed at runtime.
7433
7471
  *
@@ -7488,7 +7526,7 @@ async function hybridSearch(deps, plan) {
7488
7526
  fts: retriever.weight_fts,
7489
7527
  jaccard: retriever.weight_jaccard
7490
7528
  } : DEGRADED_WEIGHTS;
7491
- const overFetch = Math.max(limit, plan.overFetch ?? limit * (retriever.over_fetch_factor || 5));
7529
+ const overFetch = Math.max(limit, plan.overFetch ?? limit * (retriever.over_fetch_factor || defaultConfig.retriever.over_fetch_factor));
7492
7530
  const legCap = legCapFor(deps.config, overFetch);
7493
7531
  const termCount = gradedTerms(query).length;
7494
7532
  /**
@@ -8251,37 +8289,82 @@ async function forEachYielding(items, visit, every = 200) {
8251
8289
  if ((index + 1) % every === 0) await yieldToEventLoop();
8252
8290
  }
8253
8291
  }
8292
+ //#endregion
8293
+ //#region ../core/lib/store/vector_space.js
8254
8294
  /**
8255
- * Rebuild one store's live vstore from its persisted rows, count what is unusable in the current
8256
- * space, and say so once — the shared "open for business" step both stores used to write twice.
8295
+ * The ONE rule that decides whether a persisted vector can serve the store's CURRENT embedding
8296
+ * space — and therefore the one place the three counts (`stale` / `space_stale` / `legacy`) mean
8297
+ * anything.
8257
8298
  *
8258
- * The owning store's ONLY half is the row read (`facts.activeVectorRows()` /
8259
- * `chunks.vectorRows()`); the reload, the count and the loud warning are one implementation, so a
8260
- * change to what counts as stale cannot land on one store only (the incident this exists for: the
8261
- * memory store checked the SPACE while knowledge checked only the WIDTH, so a model swap mixed two
8262
- * spaces in one index until someone happened to run `kb_reindex`).
8299
+ * The rule used to be written out five times (the shared open-time reload, the memory store's cheap
8300
+ * blob-length scan, the memory store's decode pass, the knowledge store's SQL projection and its
8301
+ * encode-source predicate), each in a slightly different shape: one over `Uint8Array`, one over a
8302
+ * projected `length(blob)`, one over a decoded `Float32Array`. They happened to agree; nothing made
8303
+ * them. A change to "what counts as stale" landing on one of them is exactly the silent two-spaces-
8304
+ * in-one-index failure `reportStaleVectors` exists to announce.
8305
+ *
8306
+ * The rule, as three elements (and nothing else):
8307
+ *
8308
+ * 1. `vec == null || byteLength !== dim * 4` → `stale` (the bytes cannot even decode into the
8309
+ * current store);
8310
+ * 2. `embedding_model !== space` → `space_stale` (same width, another model's coordinates);
8311
+ * 3. of those, `isPreFingerprintSpace(...)` → `legacy` (a one-time format upgrade, not a model
8312
+ * swap).
8313
+ *
8314
+ * WHAT IS NOT HERE: the SQL mirror (`ChunksDao.vectorSpaceCounts`) stays in SQL — it is what makes a
8315
+ * per-slice migration cheap (no blob is read) — and the cross assertions in
8316
+ * `test/vector_migration.spec.ts` / `test/knowledge_vector_migration.spec.ts` bind its counts to the
8317
+ * counts this module produces and to the startup warning. That is the direction the mirror has to be
8318
+ * checked in; a JS port of the SQL query would just be a sixth copy.
8319
+ *
8320
+ * @module store/vector_space
8263
8321
  */
8264
- function loadVectorIndex(opts) {
8265
- reloadVectorIndex(opts.vstore, opts.rows, opts.store);
8266
- const expectedBytes = opts.vstore.dim * 4;
8322
+ /** How many bytes one element of a persisted vector BLOB costs (`float32ToBytes` writes LE f32). */
8323
+ const BYTES_PER_FLOAT32 = 4;
8324
+ /**
8325
+ * Classify ONE persisted vector. Pure: no store, no database, no logging — a caller that disagrees
8326
+ * with the result has to disagree with the rule, not with a copy of it.
8327
+ *
8328
+ * A caller-supplied vector is trusted to come from this backend, but its DIMENSION is still checked
8329
+ * — the same asymmetry `legs.ts` applies to a caller-supplied `queryVector`: provenance is the
8330
+ * caller's to assert, width is cheap and decides whether the bytes can be compared at all.
8331
+ */
8332
+ function classifyVectorSpace(probe, identity) {
8333
+ if (!(probe.source === "blob" ? probe.vec !== null && probe.vec !== void 0 && probe.vec.byteLength === identity.dim * BYTES_PER_FLOAT32 : probe.source === "byteLength" ? probe.byteLength === identity.dim * BYTES_PER_FLOAT32 : probe.vec !== null && probe.vec !== void 0 && probe.vec.length === identity.dim)) return {
8334
+ verdict: "stale",
8335
+ legacy: false
8336
+ };
8337
+ if (probe.embeddingModel !== identity.space) return {
8338
+ verdict: "space_stale",
8339
+ legacy: isPreFingerprintSpace(probe.embeddingModel)
8340
+ };
8341
+ return {
8342
+ verdict: "current",
8343
+ legacy: false
8344
+ };
8345
+ }
8346
+ /**
8347
+ * {@link classifyVectorSpace} over a corpus: the `{ stale, space_stale, legacy }` triple the warning
8348
+ * and the `/mem` status surface report, counted by the same rule that classified each row.
8349
+ *
8350
+ * `legacy` counts only rows already counted in `space_stale` (`reportStaleVectors` clamps it there
8351
+ * too) — it is a REASON split, never a fourth bucket.
8352
+ */
8353
+ function countVectorSpace(probes, identity) {
8267
8354
  let stale = 0;
8268
8355
  let spaceStale = 0;
8269
8356
  let legacy = 0;
8270
- for (const row of opts.rows) {
8271
- if (row.vec === null || row.vec.byteLength !== expectedBytes) {
8357
+ for (const probe of probes) {
8358
+ const classified = classifyVectorSpace(probe, identity);
8359
+ if (classified.verdict === "stale") {
8272
8360
  stale++;
8273
8361
  continue;
8274
8362
  }
8275
- if (row.embedding_model !== opts.space) {
8363
+ if (classified.verdict === "space_stale") {
8276
8364
  spaceStale++;
8277
- if (isPreFingerprintSpace(row.embedding_model)) legacy++;
8365
+ if (classified.legacy) legacy++;
8278
8366
  }
8279
8367
  }
8280
- reportStaleVectors(opts.store, opts.space, {
8281
- stale,
8282
- space_stale: spaceStale,
8283
- legacy
8284
- }, opts.manualEntry);
8285
8368
  return {
8286
8369
  stale,
8287
8370
  space_stale: spaceStale,
@@ -8289,6 +8372,29 @@ function loadVectorIndex(opts) {
8289
8372
  };
8290
8373
  }
8291
8374
  /**
8375
+ * Rebuild one store's live vstore from its persisted rows, count what is unusable in the current
8376
+ * space, and say so once — the shared "open for business" step both stores used to write twice.
8377
+ *
8378
+ * The owning store's ONLY half is the row read (`facts.activeVectorRows()` /
8379
+ * `chunks.vectorRows()`); the reload, the count and the loud warning are one implementation, so a
8380
+ * change to what counts as stale cannot land on one store only (the incident this exists for: the
8381
+ * memory store checked the SPACE while knowledge checked only the WIDTH, so a model swap mixed two
8382
+ * spaces in one index until someone happened to run `kb_reindex`).
8383
+ */
8384
+ function loadVectorIndex(opts) {
8385
+ reloadVectorIndex(opts.vstore, opts.rows, opts.store);
8386
+ const counts = countVectorSpace(opts.rows.map((row) => ({
8387
+ source: "blob",
8388
+ vec: row.vec,
8389
+ embeddingModel: row.embedding_model
8390
+ })), {
8391
+ space: opts.space,
8392
+ dim: opts.vstore.dim
8393
+ });
8394
+ reportStaleVectors(opts.store, opts.space, counts, opts.manualEntry);
8395
+ return counts;
8396
+ }
8397
+ /**
8292
8398
  * Encode rows one at a time, add each to the live index, and persist them in groups.
8293
8399
  *
8294
8400
  * The shared skeleton: serial encode (a MEASURED decision for chunks — a padded batched forward pass
@@ -10479,22 +10585,53 @@ var FactsDao = class FactsDao {
10479
10585
  //#endregion
10480
10586
  //#region ../core/lib/db/dao/fact_sources.js
10481
10587
  /**
10588
+ * The closed `kind` vocabulary, spelled once so the store and the tests share it.
10589
+ *
10590
+ * The `satisfies` pins every member to the contract's union; the `Exclude` below pins the other
10591
+ * direction, so a kind the contract ADDS fails to compile here instead of silently never being
10592
+ * recorded.
10593
+ */
10594
+ const FACT_SOURCE_KINDS = [
10595
+ "session",
10596
+ "kb_doc",
10597
+ "tool",
10598
+ "manual"
10599
+ ];
10600
+ /**
10601
+ * The FALLBACK kind: a `source_ref` without a recognized `kind:` prefix is `manual` with the
10602
+ * reference kept VERBATIM (the tool contract says so, and "no shape guessing" is the point).
10603
+ */
10604
+ const FACT_SOURCE_FALLBACK_KIND = "manual";
10605
+ /**
10606
+ * The kinds that act as a PREFIX — the vocabulary minus its own fallback, so a kind the contract adds
10607
+ * joins the prefix table by itself (via {@link FACT_SOURCE_KINDS}) and cannot be forgotten here.
10608
+ */
10609
+ const FACT_SOURCE_PREFIX_KINDS = FACT_SOURCE_KINDS.filter((kind) => kind !== FACT_SOURCE_FALLBACK_KIND);
10610
+ /**
10482
10611
  * Derive `(kind, ref)` from the single `source_ref` the write face accepts.
10483
10612
  *
10484
10613
  * The tool takes ONE string (the plan adds no second parameter), so the kind axis is spelled by a
10485
- * `kind:` prefix — `session:…` / `kb_doc:…` / `tool:…` — and anything else is `manual` with the
10486
- * reference kept VERBATIM. No shape guessing: a bare `domain:source:title` becomes a `manual`
10487
- * source whose ref is exactly what the caller wrote, which is strictly more honest than inventing
10488
- * a category from how the string looks.
10614
+ * `kind:` prefix — `session:…` / `kb_doc:…` / `tool:…` — and anything else, INCLUDING the fallback
10615
+ * kind's own name, is `manual` with the reference kept VERBATIM. No shape guessing: a bare
10616
+ * `domain:source:title` becomes a `manual` source whose ref is exactly what the caller wrote, which
10617
+ * is strictly more honest than inventing a category from how the string looks.
10618
+ *
10619
+ * The prefix table comes from {@link FACT_SOURCE_KINDS} (see {@link FACT_SOURCE_PREFIX_KINDS}) rather
10620
+ * than from a hand-written alternation, which is what keeps the recognized set and the recorded set
10621
+ * from being two lists.
10489
10622
  */
10490
10623
  function classifySourceRef(sourceRef) {
10491
- const match = /^(session|kb_doc|tool):(.+)$/s.exec(sourceRef);
10492
- if (match !== null && match[2] !== void 0) return {
10493
- kind: match[1],
10494
- ref: match[2]
10495
- };
10624
+ const separator = sourceRef.indexOf(":");
10625
+ if (separator > 0) {
10626
+ const prefix = sourceRef.slice(0, separator);
10627
+ const ref = sourceRef.slice(separator + 1);
10628
+ if (ref !== "" && FACT_SOURCE_PREFIX_KINDS.includes(prefix)) return {
10629
+ kind: prefix,
10630
+ ref
10631
+ };
10632
+ }
10496
10633
  return {
10497
- kind: "manual",
10634
+ kind: FACT_SOURCE_FALLBACK_KIND,
10498
10635
  ref: sourceRef
10499
10636
  };
10500
10637
  }
@@ -11551,26 +11688,14 @@ var MemoryStore = class {
11551
11688
  * and every existing assertion on it — is unchanged; only the warning's wording uses it.
11552
11689
  */
11553
11690
  vectorSpaceCounts() {
11554
- const space = this.vectorSpace();
11555
- const expectedBytes = this.vstore.dim * 4;
11556
- let stale = 0;
11557
- let spaceStale = 0;
11558
- let legacy = 0;
11559
- for (const row of this.facts.activeVectorSpaces()) {
11560
- if (row.bytes !== expectedBytes) {
11561
- stale++;
11562
- continue;
11563
- }
11564
- if (row.embedding_model !== space) {
11565
- spaceStale++;
11566
- if (isPreFingerprintSpace(row.embedding_model)) legacy++;
11567
- }
11568
- }
11569
- return {
11570
- stale,
11571
- space_stale: spaceStale,
11572
- legacy
11573
- };
11691
+ return countVectorSpace(this.facts.activeVectorSpaces().map((row) => ({
11692
+ source: "byteLength",
11693
+ byteLength: row.bytes,
11694
+ embeddingModel: row.embedding_model
11695
+ })), {
11696
+ space: this.vectorSpace(),
11697
+ dim: this.vstore.dim
11698
+ });
11574
11699
  }
11575
11700
  async add(content, category, ttlDays, opts) {
11576
11701
  const normalized = normalizeWrite(content).trim();
@@ -12028,17 +12153,25 @@ var MemoryStore = class {
12028
12153
  const counts = this.facts.vectorCounts();
12029
12154
  const models = this.facts.embeddingModels();
12030
12155
  const rows = this.facts.activeVectorRows();
12031
- const space = this.vectorSpace();
12156
+ const identity = {
12157
+ space: this.vectorSpace(),
12158
+ dim: this.vstore.dim
12159
+ };
12032
12160
  const staleIds = [];
12033
12161
  const spaceStaleIds = [];
12034
12162
  const usable = [];
12035
12163
  for (const r of rows) {
12036
12164
  const vec = bytesToFloat32(r.semantic_vector);
12037
- if (!vec || vec.length !== this.vstore.dim) {
12165
+ const classified = classifyVectorSpace({
12166
+ source: "decoded",
12167
+ vec,
12168
+ embeddingModel: r.embedding_model
12169
+ }, identity);
12170
+ if (classified.verdict === "stale") {
12038
12171
  staleIds.push(r.fact_id);
12039
12172
  continue;
12040
12173
  }
12041
- if (r.embedding_model !== space) spaceStaleIds.push(r.fact_id);
12174
+ if (classified.verdict === "space_stale") spaceStaleIds.push(r.fact_id);
12042
12175
  usable.push({
12043
12176
  id: r.fact_id,
12044
12177
  vec
@@ -13069,6 +13202,12 @@ var ChunksDao = class {
13069
13202
  * This is what lets the shared repair flow read "what is stale" cheaply per slice instead of
13070
13203
  * re-scanning and hashing the corpus (`corpusState` reads every text; a batched migration must
13071
13204
  * not).
13205
+ *
13206
+ * The JS rule itself is `store/vector_space.ts` (`classifyVectorSpace` / `countVectorSpace`), and
13207
+ * this projection is bound to it by the cross assertions in
13208
+ * `test/knowledge_vector_migration.spec.ts` (the startup warning's count, the health count and the
13209
+ * migration's `remaining` all have to be the same number). NOTHING here changes when the JS rule
13210
+ * changes: the mirror is checked, not shared.
13072
13211
  */
13073
13212
  vectorSpaceCounts(space, expectedBytes) {
13074
13213
  const row = this.db.prepare(`SELECT
@@ -18472,7 +18611,7 @@ async function apply(ctx, config) {
18472
18611
  logger.info(wellFormed.text && wellFormed.deep ? "well-formed repair: the base kit's wellFormedText/wellFormedDeep (interface v2)" : "well-formed repair: the mem mirror (the base is absent, or predates the v2 helpers)");
18473
18612
  const compat = env?.compat;
18474
18613
  let verdict;
18475
- if (compat === void 0) logger.warn("plugin mount: the dsh compatibility gate is ABSENT (@avantf/dsh-plugin-base unavailable — see the WARNING above); mounting the full plugin anyway");
18614
+ if (compat === void 0) logger.warn("plugin mount: the dsh compatibility gate is UNAVAILABLE (@avantf/dsh-plugin-base is absent, or it is another interface generation — see the WARNING above); mounting the full plugin anyway");
18476
18615
  else {
18477
18616
  const run = provision(ctx, logger, compat);
18478
18617
  if (!run.verdict.load) {
@@ -18634,7 +18773,8 @@ async function apply(ctx, config) {
18634
18773
  new AvantfMemGateway(ctx, rt);
18635
18774
  logger.info("remote registered: avantfMem (client ctx.remote.avantfMem.*)");
18636
18775
  const disposeTypert = ctx.typert.register(hostContribution);
18637
- logger.info("typert registered: avantfMem host face (5 tools + 5 UI-only)");
18776
+ const toolBackedMethods = descriptors.filter((descriptor) => toolSpecs.some((spec) => spec.key === descriptor.method)).length;
18777
+ logger.info(`typert registered: avantfMem host face (${String(toolBackedMethods)} tool-backed + ${String(descriptors.length - toolBackedMethods)} UI-only Remote methods)`);
18638
18778
  if (compat !== void 0) verifyRegisteredFaces({
18639
18779
  ctx,
18640
18780
  toolNames: toolSpecs.map((spec) => spec.name),
@@ -1,4 +1,4 @@
1
1
  {
2
- "baseVersion": "0.4.2",
3
- "interfaceVersion": 3
2
+ "baseVersion": "0.5.2",
3
+ "interfaceVersion": 4
4
4
  }
@@ -3,18 +3,20 @@
3
3
  * @module bootstrap
4
4
  */
5
5
  /** The bootstrap version; the resolved framework must satisfy {@link supportedRange}. */
6
- export declare const VERSION = "0.4.2";
6
+ export declare const VERSION = "0.5.2";
7
7
  /**
8
8
  * The framework interval this bootstrap can launch.
9
9
  *
10
- * Kept equal to the plugins' peer range for the base: the plugin passes no override, so THIS is the
11
- * runtime gate. It is a plain comparator interval, NOT a caret: the package version is ordinary
12
- * semver again and no longer tracks the interface, so the interval stays as wide as the family's
13
- * compatibility promise — `>=0.3.0 <1.0.0` admits every 0.x base this generation of plugins can
14
- * consume, and stops at the major that invented a new interface generation. The interface itself is
15
- * the separate, runtime axis: a base inside this interval whose `INTERFACE_VERSION` differs is judged
16
- * by the base's own gate (INTERFACE.md §1, §3) — an OLDER base degrades, a NEWER one is `ok` + a
17
- * warning (generations are additive), and neither ever refuses the mount.
10
+ * This is the PACKAGE-version window, and nothing else: the interval is byte-for-byte the range the
11
+ * plugins declare in their `dependencies` for the base (the install-time gate; the base is a plain
12
+ * dependency, not a peer) and the plugin passes no override, so THIS is the runtime gate too. It is
13
+ * a plain comparator interval, NOT a caret: the package version is ordinary semver and does not
14
+ * track the interface, so the interval stays as wide as the family's compatibility promise —
15
+ * `>=0.3.0 <1.0.0` admits every 0.x base this generation of plugins can consume. Its upper bound
16
+ * marks no generation boundary. Generation is the separate, runtime axis, judged on its own: the
17
+ * base's `INTERFACE_VERSION` is compared by the base's gate (INTERFACE.md §1, §3) — an OLDER base
18
+ * degrades to `incompatible`, a NEWER one is `ok` + a WARNING (generations are additive), and
19
+ * neither ever refuses the mount.
18
20
  */
19
21
  export declare const supportedRange = ">=0.3.0 <1.0.0";
20
22
  /** Sink for the warnings that replace a throw. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AASlD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,OAAO,EAAE,mBAAmB,EAAU,MAAM,kCAAkC,CAAA;AAE9E,OAAO,EASL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,WAAW,EAEhB,KAAK,WAAW,EACjB,MAAM,aAAa,CAAA;AACpB,OAAO,EAaL,KAAK,aAAa,EAClB,KAAK,WAAW,EAEhB,KAAK,YAAY,EACjB,KAAK,cAAc,EAEnB,KAAK,oBAAoB,EAG1B,MAAM,sBAAsB,CAAA;AAqB7B,eAAO,MAAM,IAAI,eAAe,CAAA;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAQ7E,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,aAAa,CAAA;AAEpB,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AACD,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAO3B,CAAA;AAkCF,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAOvC;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,SAAQ,mBAAmB;IACvD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAe;gBACtB,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,aAAa;IAK3C;;;;;;;;;OASG;YACW,IAAI;IAclB;;;;OAIG;IAEH,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;IAMlF,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;IAMnF,KAAK,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAKhF;;;;;OAKG;IAEH,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAOpD,KAAK,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;IAI5D;;;;OAIG;IAEG,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC;IAUnF,qFAAqF;IAE/E,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;IAUvE;;;;OAIG;IAEG,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;IAQvG;;;;OAIG;IAEG,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC;IAUpG;;;;;OAKG;IAEG,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;CAiBpE;AAmHD,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyYvE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AASlD,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,OAAO,EAAE,mBAAmB,EAAU,MAAM,kCAAkC,CAAA;AAE9E,OAAO,EASL,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,WAAW,EAEhB,KAAK,WAAW,EACjB,MAAM,aAAa,CAAA;AACpB,OAAO,EAaL,KAAK,aAAa,EAClB,KAAK,WAAW,EAEhB,KAAK,YAAY,EACjB,KAAK,cAAc,EAEnB,KAAK,oBAAoB,EAG1B,MAAM,sBAAsB,CAAA;AAqB7B,eAAO,MAAM,IAAI,eAAe,CAAA;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAQ7E,OAAO,EACL,uBAAuB,EACvB,mBAAmB,EACnB,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,aAAa,CAAA;AAEpB,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AACD,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAO3B,CAAA;AAkCF,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAOvC;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,SAAQ,mBAAmB;IACvD,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAe;gBACtB,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,aAAa;IAK3C;;;;;;;;;OASG;YACW,IAAI;IAclB;;;;OAIG;IAEH,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;IAMlF,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;IAMnF,KAAK,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;IAKhF;;;;;OAKG;IAEH,EAAE,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IAOpD,KAAK,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;IAI5D;;;;OAIG;IAEG,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC;IAUnF,qFAAqF;IAE/E,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC;IAUvE;;;;OAIG;IAEG,SAAS,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC,CAAC;IAQvG;;;;OAIG;IAEG,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC,CAAC;IAUpG;;;;;OAKG;IAEG,OAAO,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;CAiBpE;AAmHD,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyZvE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@avantf/dsh-mem",
3
- "version": "0.6.3",
3
+ "version": "0.6.4",
4
4
  "description": "avantf-mem DSH native Cordis plugin: host service + tools + RPC + client tabs 记忆/知识",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -78,10 +78,10 @@
78
78
  },
79
79
  "devDependencies": {
80
80
  "@avantf/dsh-plugin-base": ">=0.3.0 <1.0.0",
81
- "@avantf/mem": "0.6.3",
82
- "@avantf/mem-contract": "0.6.3",
83
- "@avantf/mem-convert": "0.6.3",
84
- "@avantf/mem-provision": "0.6.3",
81
+ "@avantf/mem": "0.6.4",
82
+ "@avantf/mem-contract": "0.6.4",
83
+ "@avantf/mem-convert": "0.6.4",
84
+ "@avantf/mem-provision": "0.6.4",
85
85
  "@types/node": "^22.0.0",
86
86
  "@types/react": "^18.3.0",
87
87
  "lightningcss": "^1.32.0",