context-vault 2.4.0 → 2.4.2
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/README.md +438 -0
- package/bin/cli.js +365 -69
- package/node_modules/@context-vault/core/package.json +13 -11
- package/node_modules/@context-vault/core/src/core/config.js +8 -8
- package/node_modules/@context-vault/core/src/index/db.js +5 -9
- package/node_modules/@context-vault/core/src/index/embed.js +14 -10
- package/node_modules/@context-vault/core/src/server/tools.js +61 -19
- package/package.json +34 -8
- package/scripts/local-server.js +386 -0
- package/scripts/postinstall.js +35 -2
- package/scripts/prepack.js +19 -6
- package/src/server/index.js +53 -18
- package/ui/Context.applescript +0 -36
- package/ui/index.html +0 -1377
- package/ui/serve.js +0 -474
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@context-vault/core",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared core: capture, index, retrieve, tools, and utilities for context-vault",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -21,16 +21,18 @@
|
|
|
21
21
|
"./core/frontmatter": "./src/core/frontmatter.js",
|
|
22
22
|
"./core/status": "./src/core/status.js"
|
|
23
23
|
},
|
|
24
|
-
"files": [
|
|
24
|
+
"files": [
|
|
25
|
+
"src/"
|
|
26
|
+
],
|
|
25
27
|
"license": "MIT",
|
|
26
|
-
"engines": {
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
27
31
|
"author": "Felix Hellstrom",
|
|
28
|
-
"repository": {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"sqlite-vec": "^0.1.0"
|
|
35
|
-
}
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/fellanH/context-mcp.git",
|
|
35
|
+
"directory": "packages/core"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/fellanH/context-mcp"
|
|
36
38
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Resolution chain (highest priority last):
|
|
5
5
|
* 1. Convention defaults
|
|
6
6
|
* 2. Config file (~/.context-mcp/config.json)
|
|
7
|
-
* 3. Environment variables (CONTEXT_MCP_*)
|
|
7
|
+
* 3. Environment variables (CONTEXT_VAULT_* or CONTEXT_MCP_*)
|
|
8
8
|
* 4. CLI arguments
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -29,7 +29,7 @@ export function resolveConfig() {
|
|
|
29
29
|
const cliArgs = parseArgs(process.argv);
|
|
30
30
|
|
|
31
31
|
// 1. Convention defaults
|
|
32
|
-
const dataDir = resolve(cliArgs.dataDir || process.env.CONTEXT_MCP_DATA_DIR || join(HOME, ".context-mcp"));
|
|
32
|
+
const dataDir = resolve(cliArgs.dataDir || process.env.CONTEXT_VAULT_DATA_DIR || process.env.CONTEXT_MCP_DATA_DIR || join(HOME, ".context-mcp"));
|
|
33
33
|
const config = {
|
|
34
34
|
vaultDir: join(HOME, "vault"),
|
|
35
35
|
dataDir,
|
|
@@ -51,16 +51,16 @@ export function resolveConfig() {
|
|
|
51
51
|
if (fc.eventDecayDays) config.eventDecayDays = fc.eventDecayDays;
|
|
52
52
|
config.resolvedFrom = "config file";
|
|
53
53
|
} catch (e) {
|
|
54
|
-
throw new Error(`[context-
|
|
54
|
+
throw new Error(`[context-vault] Invalid config at ${configPath}: ${e.message}`);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
config.configPath = configPath;
|
|
58
58
|
|
|
59
|
-
// 3. Environment variable overrides
|
|
60
|
-
if (process.env.CONTEXT_MCP_VAULT_DIR) { config.vaultDir = process.env.CONTEXT_MCP_VAULT_DIR; config.resolvedFrom = "env"; }
|
|
61
|
-
if (process.env.CONTEXT_MCP_DB_PATH) { config.dbPath = process.env.CONTEXT_MCP_DB_PATH; config.resolvedFrom = "env"; }
|
|
62
|
-
if (process.env.CONTEXT_MCP_DEV_DIR) { config.devDir = process.env.CONTEXT_MCP_DEV_DIR; config.resolvedFrom = "env"; }
|
|
63
|
-
if (process.env.CONTEXT_MCP_EVENT_DECAY_DAYS) { config.eventDecayDays = Number(process.env.CONTEXT_MCP_EVENT_DECAY_DAYS); config.resolvedFrom = "env"; }
|
|
59
|
+
// 3. Environment variable overrides (CONTEXT_VAULT_* takes priority over CONTEXT_MCP_*)
|
|
60
|
+
if (process.env.CONTEXT_VAULT_VAULT_DIR || process.env.CONTEXT_MCP_VAULT_DIR) { config.vaultDir = process.env.CONTEXT_VAULT_VAULT_DIR || process.env.CONTEXT_MCP_VAULT_DIR; config.resolvedFrom = "env"; }
|
|
61
|
+
if (process.env.CONTEXT_VAULT_DB_PATH || process.env.CONTEXT_MCP_DB_PATH) { config.dbPath = process.env.CONTEXT_VAULT_DB_PATH || process.env.CONTEXT_MCP_DB_PATH; config.resolvedFrom = "env"; }
|
|
62
|
+
if (process.env.CONTEXT_VAULT_DEV_DIR || process.env.CONTEXT_MCP_DEV_DIR) { config.devDir = process.env.CONTEXT_VAULT_DEV_DIR || process.env.CONTEXT_MCP_DEV_DIR; config.resolvedFrom = "env"; }
|
|
63
|
+
if (process.env.CONTEXT_VAULT_EVENT_DECAY_DAYS || process.env.CONTEXT_MCP_EVENT_DECAY_DAYS) { config.eventDecayDays = Number(process.env.CONTEXT_VAULT_EVENT_DECAY_DAYS || process.env.CONTEXT_MCP_EVENT_DECAY_DAYS); config.resolvedFrom = "env"; }
|
|
64
64
|
|
|
65
65
|
// 4. CLI arg overrides (highest priority)
|
|
66
66
|
if (cliArgs.vaultDir) { config.vaultDir = cliArgs.vaultDir; config.resolvedFrom = "CLI args"; }
|
|
@@ -136,11 +136,7 @@ export async function initDatabase(dbPath) {
|
|
|
136
136
|
try {
|
|
137
137
|
sqliteVec.load(db);
|
|
138
138
|
} catch (e) {
|
|
139
|
-
|
|
140
|
-
console.error(`[context-mcp] This usually means prebuilt binaries aren't available for your platform.`);
|
|
141
|
-
console.error(`[context-mcp] Try: npm rebuild sqlite-vec`);
|
|
142
|
-
console.error(`[context-mcp] Error: ${e.message}`);
|
|
143
|
-
throw e;
|
|
139
|
+
throw new NativeModuleError(e);
|
|
144
140
|
}
|
|
145
141
|
return db;
|
|
146
142
|
}
|
|
@@ -150,7 +146,7 @@ export async function initDatabase(dbPath) {
|
|
|
150
146
|
|
|
151
147
|
// Enforce fresh-DB-only — old schemas get a full rebuild (with backup)
|
|
152
148
|
if (version > 0 && version < 5) {
|
|
153
|
-
console.error(`[context-
|
|
149
|
+
console.error(`[context-vault] Schema v${version} is outdated. Rebuilding database...`);
|
|
154
150
|
|
|
155
151
|
// Backup old DB before destroying it
|
|
156
152
|
const backupPath = `${dbPath}.v${version}.backup`;
|
|
@@ -158,10 +154,10 @@ export async function initDatabase(dbPath) {
|
|
|
158
154
|
db.close();
|
|
159
155
|
if (existsSync(dbPath)) {
|
|
160
156
|
copyFileSync(dbPath, backupPath);
|
|
161
|
-
console.error(`[context-
|
|
157
|
+
console.error(`[context-vault] Backed up old database to: ${backupPath}`);
|
|
162
158
|
}
|
|
163
159
|
} catch (backupErr) {
|
|
164
|
-
console.error(`[context-
|
|
160
|
+
console.error(`[context-vault] Warning: could not backup old database: ${backupErr.message}`);
|
|
165
161
|
}
|
|
166
162
|
|
|
167
163
|
unlinkSync(dbPath);
|
|
@@ -222,7 +218,7 @@ export function prepareStatements(db) {
|
|
|
222
218
|
} catch (e) {
|
|
223
219
|
throw new Error(
|
|
224
220
|
`Failed to prepare database statements. The database may be corrupted.\n` +
|
|
225
|
-
`Try deleting and rebuilding: rm "${db.name}" && context-
|
|
221
|
+
`Try deleting and rebuilding: rm "${db.name}" && context-vault reindex\n` +
|
|
226
222
|
`Original error: ${e.message}`
|
|
227
223
|
);
|
|
228
224
|
}
|
|
@@ -5,17 +5,10 @@
|
|
|
5
5
|
* disk issues), semantic search is disabled but FTS still works.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { pipeline, env } from "@huggingface/transformers";
|
|
9
8
|
import { join } from "node:path";
|
|
10
9
|
import { homedir } from "node:os";
|
|
11
10
|
import { mkdirSync } from "node:fs";
|
|
12
11
|
|
|
13
|
-
// Redirect model cache to ~/.context-mcp/models/ so it works when the
|
|
14
|
-
// package is installed globally in a root-owned directory (e.g. /usr/lib/node_modules/).
|
|
15
|
-
const modelCacheDir = join(homedir(), ".context-mcp", "models");
|
|
16
|
-
mkdirSync(modelCacheDir, { recursive: true });
|
|
17
|
-
env.cacheDir = modelCacheDir;
|
|
18
|
-
|
|
19
12
|
let extractor = null;
|
|
20
13
|
|
|
21
14
|
/** @type {null | true | false} null = unknown, true = working, false = failed */
|
|
@@ -26,14 +19,25 @@ async function ensurePipeline() {
|
|
|
26
19
|
if (extractor) return extractor;
|
|
27
20
|
|
|
28
21
|
try {
|
|
29
|
-
|
|
22
|
+
// Dynamic import — @huggingface/transformers is optional (its transitive
|
|
23
|
+
// dep `sharp` can fail to install on some platforms). When missing, the
|
|
24
|
+
// server still works with full-text search only.
|
|
25
|
+
const { pipeline, env } = await import("@huggingface/transformers");
|
|
26
|
+
|
|
27
|
+
// Redirect model cache to ~/.context-mcp/models/ so it works when the
|
|
28
|
+
// package is installed globally in a root-owned directory (e.g. /usr/lib/node_modules/).
|
|
29
|
+
const modelCacheDir = join(homedir(), ".context-mcp", "models");
|
|
30
|
+
mkdirSync(modelCacheDir, { recursive: true });
|
|
31
|
+
env.cacheDir = modelCacheDir;
|
|
32
|
+
|
|
33
|
+
console.error("[context-vault] Loading embedding model (first run may download ~22MB)...");
|
|
30
34
|
extractor = await pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
|
|
31
35
|
embedAvailable = true;
|
|
32
36
|
return extractor;
|
|
33
37
|
} catch (e) {
|
|
34
38
|
embedAvailable = false;
|
|
35
|
-
console.error(`[context-
|
|
36
|
-
console.error(`[context-
|
|
39
|
+
console.error(`[context-vault] Failed to load embedding model: ${e.message}`);
|
|
40
|
+
console.error(`[context-vault] Semantic search disabled. Full-text search still works.`);
|
|
37
41
|
return null;
|
|
38
42
|
}
|
|
39
43
|
}
|
|
@@ -16,6 +16,7 @@ import { gatherVaultStatus } from "../core/status.js";
|
|
|
16
16
|
import { categoryFor } from "../core/categories.js";
|
|
17
17
|
import { normalizeKind } from "../core/files.js";
|
|
18
18
|
import { ok, err, ensureVaultExists, ensureValidKind } from "./helpers.js";
|
|
19
|
+
import { isEmbedAvailable } from "../index/embed.js";
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Register all MCP tools on the server.
|
|
@@ -23,10 +24,37 @@ import { ok, err, ensureVaultExists, ensureValidKind } from "./helpers.js";
|
|
|
23
24
|
* @param {import("@modelcontextprotocol/sdk/server/mcp.js").McpServer} server
|
|
24
25
|
* @param {{ db, config, stmts, embed, insertVec, deleteVec }} ctx
|
|
25
26
|
*/
|
|
27
|
+
const TOOL_TIMEOUT_MS = 60_000;
|
|
28
|
+
|
|
26
29
|
export function registerTools(server, ctx) {
|
|
27
30
|
const { config } = ctx;
|
|
28
31
|
const userId = ctx.userId !== undefined ? ctx.userId : undefined;
|
|
29
32
|
|
|
33
|
+
// ─── Tool wrapper: tracks in-flight ops for graceful shutdown + timeout ────
|
|
34
|
+
|
|
35
|
+
function tracked(handler) {
|
|
36
|
+
return async (...args) => {
|
|
37
|
+
if (ctx.activeOps) ctx.activeOps.count++;
|
|
38
|
+
let timer;
|
|
39
|
+
try {
|
|
40
|
+
return await Promise.race([
|
|
41
|
+
Promise.resolve(handler(...args)),
|
|
42
|
+
new Promise((_, reject) => {
|
|
43
|
+
timer = setTimeout(() => reject(new Error("TOOL_TIMEOUT")), TOOL_TIMEOUT_MS);
|
|
44
|
+
}),
|
|
45
|
+
]);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
if (e.message === "TOOL_TIMEOUT") {
|
|
48
|
+
return err("Tool timed out after 60s. Try a simpler query or run `context-vault reindex` first.", "TIMEOUT");
|
|
49
|
+
}
|
|
50
|
+
throw e;
|
|
51
|
+
} finally {
|
|
52
|
+
clearTimeout(timer);
|
|
53
|
+
if (ctx.activeOps) ctx.activeOps.count--;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
30
58
|
// ─── Auto-Reindex (runs once per session, on first tool call) ──────────────
|
|
31
59
|
|
|
32
60
|
// In hosted mode, skip reindex — DB is always in sync via writeEntry→indexEntry
|
|
@@ -44,14 +72,14 @@ export function registerTools(server, ctx) {
|
|
|
44
72
|
reindexDone = true;
|
|
45
73
|
const total = stats.added + stats.updated + stats.removed;
|
|
46
74
|
if (total > 0) {
|
|
47
|
-
console.error(`[context-
|
|
75
|
+
console.error(`[context-vault] Auto-reindex: +${stats.added} ~${stats.updated} -${stats.removed} (${stats.unchanged} unchanged)`);
|
|
48
76
|
}
|
|
49
77
|
})
|
|
50
78
|
.catch((e) => {
|
|
51
79
|
reindexAttempts++;
|
|
52
|
-
console.error(`[context-
|
|
80
|
+
console.error(`[context-vault] Auto-reindex failed (attempt ${reindexAttempts}/${MAX_REINDEX_ATTEMPTS}): ${e.message}`);
|
|
53
81
|
if (reindexAttempts >= MAX_REINDEX_ATTEMPTS) {
|
|
54
|
-
console.error(`[context-
|
|
82
|
+
console.error(`[context-vault] Giving up on auto-reindex. Run \`context-vault reindex\` manually to diagnose.`);
|
|
55
83
|
reindexDone = true;
|
|
56
84
|
reindexFailed = true;
|
|
57
85
|
} else {
|
|
@@ -76,7 +104,7 @@ export function registerTools(server, ctx) {
|
|
|
76
104
|
until: z.string().optional().describe("ISO date, return entries created before this"),
|
|
77
105
|
limit: z.number().optional().describe("Max results to return (default 10)"),
|
|
78
106
|
},
|
|
79
|
-
async ({ query, kind, category, identity_key, tags, since, until, limit }) => {
|
|
107
|
+
tracked(async ({ query, kind, category, identity_key, tags, since, until, limit }) => {
|
|
80
108
|
const hasQuery = query?.trim();
|
|
81
109
|
const hasFilters = kind || category || tags?.length || since || until || identity_key;
|
|
82
110
|
if (!hasQuery && !hasFilters) return err("Required: query or at least one filter (kind, category, tags, since, until, identity_key)", "INVALID_INPUT");
|
|
@@ -175,7 +203,8 @@ export function registerTools(server, ctx) {
|
|
|
175
203
|
}
|
|
176
204
|
|
|
177
205
|
const lines = [];
|
|
178
|
-
if (reindexFailed) lines.push(`> **Warning:** Auto-reindex failed. Results may be stale. Run \`context-
|
|
206
|
+
if (reindexFailed) lines.push(`> **Warning:** Auto-reindex failed. Results may be stale. Run \`context-vault reindex\` to fix.\n`);
|
|
207
|
+
if (hasQuery && isEmbedAvailable() === false) lines.push(`> **Note:** Semantic search unavailable — results ranked by keyword match only. Run \`context-vault setup\` to download the embedding model.\n`);
|
|
179
208
|
const heading = hasQuery ? `Results for "${query}"` : "Filtered entries";
|
|
180
209
|
lines.push(`## ${heading} (${filtered.length} matches)\n`);
|
|
181
210
|
for (let i = 0; i < filtered.length; i++) {
|
|
@@ -192,7 +221,7 @@ export function registerTools(server, ctx) {
|
|
|
192
221
|
lines.push(`_Showing events from last ${config.eventDecayDays || 30} days. Use since/until for custom range._`);
|
|
193
222
|
}
|
|
194
223
|
return ok(lines.join("\n"));
|
|
195
|
-
}
|
|
224
|
+
})
|
|
196
225
|
);
|
|
197
226
|
|
|
198
227
|
// ─── save_context (write / update) ────────────────────────────────────────
|
|
@@ -212,7 +241,7 @@ export function registerTools(server, ctx) {
|
|
|
212
241
|
identity_key: z.string().optional().describe("Required for entity kinds (contact, project, tool, source). The unique identifier for this entity."),
|
|
213
242
|
expires_at: z.string().optional().describe("ISO date for TTL expiry"),
|
|
214
243
|
},
|
|
215
|
-
async ({ id, kind, title, body, tags, meta, folder, source, identity_key, expires_at }) => {
|
|
244
|
+
tracked(async ({ id, kind, title, body, tags, meta, folder, source, identity_key, expires_at }) => {
|
|
216
245
|
const vaultErr = ensureVaultExists(config);
|
|
217
246
|
if (vaultErr) return vaultErr;
|
|
218
247
|
|
|
@@ -264,6 +293,17 @@ export function registerTools(server, ctx) {
|
|
|
264
293
|
return err(`Entity kind "${kind}" requires identity_key`, "MISSING_IDENTITY_KEY");
|
|
265
294
|
}
|
|
266
295
|
|
|
296
|
+
// Hosted tier limit enforcement (skipped in local mode — no checkLimits on ctx)
|
|
297
|
+
if (ctx.checkLimits) {
|
|
298
|
+
const usage = ctx.checkLimits();
|
|
299
|
+
if (usage.entryCount >= usage.maxEntries) {
|
|
300
|
+
return err(`Entry limit reached (${usage.maxEntries}). Upgrade to Pro for unlimited entries.`, "LIMIT_EXCEEDED");
|
|
301
|
+
}
|
|
302
|
+
if (usage.storageMb >= usage.maxStorageMb) {
|
|
303
|
+
return err(`Storage limit reached (${usage.maxStorageMb} MB). Upgrade to Pro for more storage.`, "LIMIT_EXCEEDED");
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
267
307
|
await ensureIndexed();
|
|
268
308
|
|
|
269
309
|
const mergedMeta = { ...(meta || {}) };
|
|
@@ -277,7 +317,7 @@ export function registerTools(server, ctx) {
|
|
|
277
317
|
if (tags?.length) parts.push(` tags: ${tags.join(", ")}`);
|
|
278
318
|
parts.push("", "_Use this id to update or delete later._");
|
|
279
319
|
return ok(parts.join("\n"));
|
|
280
|
-
}
|
|
320
|
+
})
|
|
281
321
|
);
|
|
282
322
|
|
|
283
323
|
// ─── list_context (browse) ────────────────────────────────────────────────
|
|
@@ -294,7 +334,7 @@ export function registerTools(server, ctx) {
|
|
|
294
334
|
limit: z.number().optional().describe("Max results to return (default 20, max 100)"),
|
|
295
335
|
offset: z.number().optional().describe("Skip first N results for pagination"),
|
|
296
336
|
},
|
|
297
|
-
async ({ kind, category, tags, since, until, limit, offset }) => {
|
|
337
|
+
tracked(async ({ kind, category, tags, since, until, limit, offset }) => {
|
|
298
338
|
await ensureIndexed();
|
|
299
339
|
|
|
300
340
|
const clauses = [];
|
|
@@ -342,7 +382,9 @@ export function registerTools(server, ctx) {
|
|
|
342
382
|
|
|
343
383
|
if (!filtered.length) return ok("No entries found matching the given filters.");
|
|
344
384
|
|
|
345
|
-
const lines = [
|
|
385
|
+
const lines = [];
|
|
386
|
+
if (reindexFailed) lines.push(`> **Warning:** Auto-reindex failed. Results may be stale. Run \`context-vault reindex\` to fix.\n`);
|
|
387
|
+
lines.push(`## Vault Entries (${filtered.length} shown, ${total} total)\n`);
|
|
346
388
|
for (const r of filtered) {
|
|
347
389
|
const entryTags = r.tags ? JSON.parse(r.tags) : [];
|
|
348
390
|
const tagStr = entryTags.length ? entryTags.join(", ") : "none";
|
|
@@ -355,7 +397,7 @@ export function registerTools(server, ctx) {
|
|
|
355
397
|
}
|
|
356
398
|
|
|
357
399
|
return ok(lines.join("\n"));
|
|
358
|
-
}
|
|
400
|
+
})
|
|
359
401
|
);
|
|
360
402
|
|
|
361
403
|
// ─── delete_context (remove) ──────────────────────────────────────────────
|
|
@@ -366,7 +408,7 @@ export function registerTools(server, ctx) {
|
|
|
366
408
|
{
|
|
367
409
|
id: z.string().describe("The entry ULID to delete"),
|
|
368
410
|
},
|
|
369
|
-
async ({ id }) => {
|
|
411
|
+
tracked(async ({ id }) => {
|
|
370
412
|
if (!id?.trim()) return err("Required: id (non-empty string)", "INVALID_INPUT");
|
|
371
413
|
await ensureIndexed();
|
|
372
414
|
|
|
@@ -393,7 +435,7 @@ export function registerTools(server, ctx) {
|
|
|
393
435
|
ctx.stmts.deleteEntry.run(id);
|
|
394
436
|
|
|
395
437
|
return ok(`Deleted ${entry.kind}: ${entry.title || "(untitled)"} [${id}]`);
|
|
396
|
-
}
|
|
438
|
+
})
|
|
397
439
|
);
|
|
398
440
|
|
|
399
441
|
// ─── submit_feedback (bug/feature reports) ────────────────────────────────
|
|
@@ -407,7 +449,7 @@ export function registerTools(server, ctx) {
|
|
|
407
449
|
body: z.string().describe("Detailed description"),
|
|
408
450
|
severity: z.enum(["low", "medium", "high"]).optional().describe("Severity level (default: medium)"),
|
|
409
451
|
},
|
|
410
|
-
async ({ type, title, body, severity }) => {
|
|
452
|
+
tracked(async ({ type, title, body, severity }) => {
|
|
411
453
|
const vaultErr = ensureVaultExists(config);
|
|
412
454
|
if (vaultErr) return vaultErr;
|
|
413
455
|
|
|
@@ -430,7 +472,7 @@ export function registerTools(server, ctx) {
|
|
|
430
472
|
|
|
431
473
|
const relPath = entry.filePath ? entry.filePath.replace(config.vaultDir + "/", "") : entry.filePath;
|
|
432
474
|
return ok(`Feedback submitted: ${type} [${effectiveSeverity}] → ${relPath}\n id: ${entry.id}\n title: ${title}`);
|
|
433
|
-
}
|
|
475
|
+
})
|
|
434
476
|
);
|
|
435
477
|
|
|
436
478
|
// ─── context_status (diagnostics) ──────────────────────────────────────────
|
|
@@ -446,7 +488,7 @@ export function registerTools(server, ctx) {
|
|
|
446
488
|
const healthIcon = hasIssues ? "⚠" : "✓";
|
|
447
489
|
|
|
448
490
|
const lines = [
|
|
449
|
-
`## ${healthIcon} Vault Status`,
|
|
491
|
+
`## ${healthIcon} Vault Status (connected)`,
|
|
450
492
|
``,
|
|
451
493
|
`Vault: ${config.vaultDir} (${config.vaultDirExists ? status.fileCount + " files" : "missing"})`,
|
|
452
494
|
`Database: ${config.dbPath} (${status.dbSize})`,
|
|
@@ -501,9 +543,9 @@ export function registerTools(server, ctx) {
|
|
|
501
543
|
|
|
502
544
|
// Suggested actions
|
|
503
545
|
const actions = [];
|
|
504
|
-
if (status.stalePaths) actions.push("- Run `context-
|
|
505
|
-
if (status.embeddingStatus?.missing > 0) actions.push("- Run `context-
|
|
506
|
-
if (!config.vaultDirExists) actions.push("- Run `context-
|
|
546
|
+
if (status.stalePaths) actions.push("- Run `context-vault reindex` to fix stale paths");
|
|
547
|
+
if (status.embeddingStatus?.missing > 0) actions.push("- Run `context-vault reindex` to generate missing embeddings");
|
|
548
|
+
if (!config.vaultDirExists) actions.push("- Run `context-vault setup` to create the vault directory");
|
|
507
549
|
if (status.kindCounts.length === 0 && config.vaultDirExists) actions.push("- Use `save_context` to add your first entry");
|
|
508
550
|
|
|
509
551
|
if (actions.length) {
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-vault",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Persistent memory for AI agents — saves and searches knowledge across sessions",
|
|
6
6
|
"bin": {
|
|
7
|
+
"context-vault": "bin/cli.js",
|
|
7
8
|
"context-mcp": "bin/cli.js"
|
|
8
9
|
},
|
|
9
10
|
"main": "src/server/index.js",
|
|
@@ -19,19 +20,44 @@
|
|
|
19
20
|
"bin/",
|
|
20
21
|
"src/",
|
|
21
22
|
"scripts/",
|
|
22
|
-
"ui/",
|
|
23
23
|
"README.md",
|
|
24
24
|
"LICENSE"
|
|
25
25
|
],
|
|
26
26
|
"license": "MIT",
|
|
27
|
-
"engines": {
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20"
|
|
29
|
+
},
|
|
28
30
|
"author": "Felix Hellstrom",
|
|
29
|
-
"repository": {
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/fellanH/context-mcp.git"
|
|
34
|
+
},
|
|
30
35
|
"homepage": "https://github.com/fellanH/context-mcp",
|
|
31
|
-
"bugs": {
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/fellanH/context-mcp/issues"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"mcp",
|
|
41
|
+
"model-context-protocol",
|
|
42
|
+
"ai",
|
|
43
|
+
"knowledge-base",
|
|
44
|
+
"knowledge-management",
|
|
45
|
+
"vault",
|
|
46
|
+
"rag",
|
|
47
|
+
"sqlite",
|
|
48
|
+
"embeddings",
|
|
49
|
+
"claude",
|
|
50
|
+
"cursor",
|
|
51
|
+
"cline",
|
|
52
|
+
"windsurf"
|
|
53
|
+
],
|
|
54
|
+
"bundledDependencies": [
|
|
55
|
+
"@context-vault/core"
|
|
56
|
+
],
|
|
34
57
|
"dependencies": {
|
|
35
|
-
"@context-vault/core": "^2.4.
|
|
58
|
+
"@context-vault/core": "^2.4.2",
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
60
|
+
"better-sqlite3": "^12.6.2",
|
|
61
|
+
"sqlite-vec": "^0.1.0"
|
|
36
62
|
}
|
|
37
63
|
}
|