context-vault 3.0.2 → 3.0.3

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/bin/cli.js CHANGED
@@ -3598,6 +3598,8 @@ async function runSave() {
3598
3598
  const tier = getFlag("--tier");
3599
3599
  const filePath = getFlag("--file");
3600
3600
  const bodyFlag = getFlag("--body");
3601
+ const identityKey = getFlag("--identity-key");
3602
+ const metaRaw = getFlag("--meta");
3601
3603
 
3602
3604
  if (!kind) {
3603
3605
  console.error(red("Error: --kind is required"));
@@ -3608,6 +3610,16 @@ async function runSave() {
3608
3610
  process.exit(1);
3609
3611
  }
3610
3612
 
3613
+ let meta;
3614
+ if (metaRaw) {
3615
+ try {
3616
+ meta = JSON.parse(metaRaw);
3617
+ } catch {
3618
+ console.error(red("Error: --meta must be valid JSON"));
3619
+ process.exit(1);
3620
+ }
3621
+ }
3622
+
3611
3623
  let body;
3612
3624
  if (bodyFlag) {
3613
3625
  body = bodyFlag;
@@ -3665,6 +3677,8 @@ async function runSave() {
3665
3677
  tags: parsedTags,
3666
3678
  source,
3667
3679
  ...(tier ? { tier } : {}),
3680
+ ...(identityKey ? { identity_key: identityKey } : {}),
3681
+ ...(meta !== undefined ? { meta } : {}),
3668
3682
  });
3669
3683
  console.log(`${green("✓")} Saved ${kind} — id: ${entry.id}`);
3670
3684
  } catch (e) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@context-vault/core",
3
- "version": "3.0.0",
3
+ "version": "3.0.3",
4
4
  "type": "module",
5
5
  "description": "Pure local engine: capture, index, search, and utilities for context-vault",
6
6
  "main": "dist/main.js",
@@ -266,7 +266,7 @@ export function updateEntryFile(
266
266
  };
267
267
  }
268
268
 
269
- export async function captureAndIndex(ctx: BaseCtx, data: CaptureInput): Promise<CaptureResult> {
269
+ export async function captureAndIndex(ctx: BaseCtx, data: CaptureInput, precomputedEmbedding?: Float32Array | null): Promise<CaptureResult> {
270
270
  let previousContent: string | null = null;
271
271
  if (categoryFor(data.kind) === "entity" && data.identity_key) {
272
272
  const identitySlug = slugify(data.identity_key);
@@ -279,7 +279,7 @@ export async function captureAndIndex(ctx: BaseCtx, data: CaptureInput): Promise
279
279
 
280
280
  const entry = writeEntry(ctx, data);
281
281
  try {
282
- await indexEntry(ctx, entry);
282
+ await indexEntry(ctx, entry, precomputedEmbedding);
283
283
  if (entry.supersedes?.length && ctx.stmts.updateSupersededBy) {
284
284
  for (const supersededId of entry.supersedes) {
285
285
  if (typeof supersededId === "string" && supersededId.trim()) {
@@ -13,6 +13,7 @@ const EMBED_BATCH_SIZE = 32;
13
13
  export async function indexEntry(
14
14
  ctx: BaseCtx,
15
15
  entry: IndexEntryInput & { supersedes?: string[] | null; related_to?: string[] | null },
16
+ precomputedEmbedding?: Float32Array | null,
16
17
  ): Promise<void> {
17
18
  const {
18
19
  id, kind, category, title, body, meta, tags, source,
@@ -92,8 +93,9 @@ export async function indexEntry(
92
93
  }
93
94
 
94
95
  if (cat !== "event") {
95
- const embeddingText = [title, body].filter(Boolean).join(" ");
96
- const embedding = await ctx.embed(embeddingText);
96
+ const embedding = precomputedEmbedding !== undefined
97
+ ? precomputedEmbedding
98
+ : await ctx.embed([title, body].filter(Boolean).join(" "));
97
99
 
98
100
  if (embedding) {
99
101
  try { ctx.deleteVec(rowid); } catch { /* no-op */ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-vault",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
4
4
  "type": "module",
5
5
  "description": "Persistent memory for AI agents — saves and searches knowledge across sessions",
6
6
  "bin": {
@@ -57,7 +57,7 @@
57
57
  "@context-vault/core"
58
58
  ],
59
59
  "dependencies": {
60
- "@context-vault/core": "^3.0.0",
60
+ "@context-vault/core": "^3.0.3",
61
61
  "@modelcontextprotocol/sdk": "^1.26.0",
62
62
  "adm-zip": "^0.5.16",
63
63
  "sqlite-vec": "^0.1.0"
@@ -170,4 +170,6 @@ export function registerTools(server, ctx) {
170
170
  tracked((args) => mod.handler(args, ctx, shared), mod.name),
171
171
  );
172
172
  }
173
+
174
+ ensureIndexed().catch(() => {});
173
175
  }
@@ -484,17 +484,18 @@ export async function handler(
484
484
  // ── Similarity check (knowledge + event only) ────────────────────────────
485
485
  const category = categoryFor(normalizedKind);
486
486
  let similarEntries = [];
487
+ let queryEmbedding = null;
487
488
 
488
489
  if (category === "knowledge" || category === "event") {
489
490
  const threshold = similarity_threshold ?? DEFAULT_SIMILARITY_THRESHOLD;
490
491
  const embeddingText = [title, body].filter(Boolean).join(" ");
491
- const queryEmbedding = await ctx.embed(embeddingText);
492
+ queryEmbedding = await ctx.embed(embeddingText);
492
493
  if (queryEmbedding) {
493
494
  similarEntries = await findSimilar(
494
495
  ctx,
495
496
  queryEmbedding,
496
497
  threshold,
497
-
498
+
498
499
  { hydrate: suggestMode },
499
500
  );
500
501
  }
@@ -540,6 +541,8 @@ export async function handler(
540
541
 
541
542
  const effectiveTier = tier ?? defaultTierFor(normalizedKind);
542
543
 
544
+ const embeddingToReuse = category === "knowledge" ? queryEmbedding : null;
545
+
543
546
  const entry = await captureAndIndex(ctx, {
544
547
  kind: normalizedKind,
545
548
  title,
@@ -553,9 +556,9 @@ export async function handler(
553
556
  supersedes,
554
557
  related_to,
555
558
  source_files,
556
-
559
+
557
560
  tier: effectiveTier,
558
- });
561
+ }, embeddingToReuse);
559
562
 
560
563
  if (ctx.config?.dataDir) {
561
564
  maybeShowFeedbackPrompt(ctx.config.dataDir);