context-vault 3.13.0 → 3.16.0
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 +275 -0
- package/dist/error-log.d.ts +2 -0
- package/dist/error-log.d.ts.map +1 -1
- package/dist/error-log.js +31 -1
- package/dist/error-log.js.map +1 -1
- package/dist/server.js +32 -2
- package/dist/server.js.map +1 -1
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +17 -0
- package/dist/status.js.map +1 -1
- package/dist/tools/context-status.d.ts.map +1 -1
- package/dist/tools/context-status.js +26 -1
- package/dist/tools/context-status.js.map +1 -1
- package/dist/tools/delete-context.d.ts +1 -1
- package/dist/tools/delete-context.d.ts.map +1 -1
- package/dist/tools/delete-context.js +15 -2
- package/dist/tools/delete-context.js.map +1 -1
- package/dist/tools/get-context.d.ts.map +1 -1
- package/dist/tools/get-context.js +3 -2
- package/dist/tools/get-context.js.map +1 -1
- package/dist/tools/list-context.d.ts +7 -15
- package/dist/tools/list-context.d.ts.map +1 -1
- package/dist/tools/list-context.js +570 -111
- package/dist/tools/list-context.js.map +1 -1
- package/dist/tools/publish-to-team.js +1 -1
- package/dist/tools/publish-to-team.js.map +1 -1
- package/dist/tools/save-context.js +2 -2
- package/dist/tools/save-context.js.map +1 -1
- package/dist/tools/session-start.d.ts +20 -7
- package/dist/tools/session-start.d.ts.map +1 -1
- package/dist/tools/session-start.js +406 -439
- package/dist/tools/session-start.js.map +1 -1
- package/node_modules/@context-vault/core/dist/capture.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/capture.js +4 -0
- package/node_modules/@context-vault/core/dist/capture.js.map +1 -1
- package/node_modules/@context-vault/core/dist/categories.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/categories.js +8 -0
- package/node_modules/@context-vault/core/dist/categories.js.map +1 -1
- package/node_modules/@context-vault/core/dist/compact.d.ts +38 -0
- package/node_modules/@context-vault/core/dist/compact.d.ts.map +1 -0
- package/node_modules/@context-vault/core/dist/compact.js +127 -0
- package/node_modules/@context-vault/core/dist/compact.js.map +1 -0
- package/node_modules/@context-vault/core/dist/config.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/config.js +12 -0
- package/node_modules/@context-vault/core/dist/config.js.map +1 -1
- package/node_modules/@context-vault/core/dist/db.d.ts +1 -1
- package/node_modules/@context-vault/core/dist/db.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/db.js +40 -4
- package/node_modules/@context-vault/core/dist/db.js.map +1 -1
- package/node_modules/@context-vault/core/dist/main.d.ts +6 -2
- package/node_modules/@context-vault/core/dist/main.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/main.js +5 -1
- package/node_modules/@context-vault/core/dist/main.js.map +1 -1
- package/node_modules/@context-vault/core/dist/search.d.ts +13 -1
- package/node_modules/@context-vault/core/dist/search.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/search.js +50 -5
- package/node_modules/@context-vault/core/dist/search.js.map +1 -1
- package/node_modules/@context-vault/core/dist/tier-analysis.d.ts +36 -0
- package/node_modules/@context-vault/core/dist/tier-analysis.d.ts.map +1 -0
- package/node_modules/@context-vault/core/dist/tier-analysis.js +227 -0
- package/node_modules/@context-vault/core/dist/tier-analysis.js.map +1 -0
- package/node_modules/@context-vault/core/dist/types.d.ts +12 -0
- package/node_modules/@context-vault/core/dist/types.d.ts.map +1 -1
- package/node_modules/@context-vault/core/dist/watch.d.ts +21 -0
- package/node_modules/@context-vault/core/dist/watch.d.ts.map +1 -0
- package/node_modules/@context-vault/core/dist/watch.js +230 -0
- package/node_modules/@context-vault/core/dist/watch.js.map +1 -0
- package/node_modules/@context-vault/core/package.json +13 -1
- package/node_modules/@context-vault/core/src/capture.ts +4 -0
- package/node_modules/@context-vault/core/src/categories.ts +8 -0
- package/node_modules/@context-vault/core/src/compact.ts +183 -0
- package/node_modules/@context-vault/core/src/config.ts +8 -0
- package/node_modules/@context-vault/core/src/db.ts +40 -4
- package/node_modules/@context-vault/core/src/main.ts +10 -0
- package/node_modules/@context-vault/core/src/search.ts +55 -4
- package/node_modules/@context-vault/core/src/tier-analysis.ts +299 -0
- package/node_modules/@context-vault/core/src/types.ts +10 -0
- package/node_modules/@context-vault/core/src/watch.ts +269 -0
- package/package.json +2 -2
- package/src/error-log.ts +30 -0
- package/src/server.ts +31 -2
- package/src/status.ts +17 -0
- package/src/tools/context-status.ts +30 -1
- package/src/tools/delete-context.ts +10 -5
- package/src/tools/get-context.ts +3 -2
- package/src/tools/list-context.ts +620 -119
- package/src/tools/publish-to-team.ts +1 -1
- package/src/tools/save-context.ts +2 -2
- package/src/tools/session-start.ts +444 -484
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,YAAY,CAAC;IACrB,aAAa,EAAE,mBAAmB,CAAC;IACnC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,YAAY,EAAE,kBAAkB,CAAC;IACjC,QAAQ,EAAE,cAAc,CAAC;IACzB,MAAM,CAAC,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BaseCtx, IndexingConfig } from './types.js';
|
|
2
|
+
export interface WatcherOptions {
|
|
3
|
+
vaultDir: string;
|
|
4
|
+
debounceMs?: number;
|
|
5
|
+
indexingConfig?: IndexingConfig;
|
|
6
|
+
onIndex?: (filePath: string, action: 'upsert' | 'delete') => void;
|
|
7
|
+
onError?: (err: Error) => void;
|
|
8
|
+
/** Max concurrent file processing operations. Default 3. */
|
|
9
|
+
maxConcurrency?: number;
|
|
10
|
+
/** Max events queued before dropping oldest. Default 200. */
|
|
11
|
+
maxQueueSize?: number;
|
|
12
|
+
/** Data directory for the lock file (e.g. ~/.context-mcp). */
|
|
13
|
+
dataDir?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface VaultWatcher {
|
|
16
|
+
close: () => void;
|
|
17
|
+
/** Mark a path as self-written so the watcher skips it. TTL: 2 seconds. */
|
|
18
|
+
markSelfWrite: (filePath: string) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare function startWatcher(ctx: BaseCtx, opts: WatcherOptions): VaultWatcher;
|
|
21
|
+
//# sourceMappingURL=watch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAO1D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,GAAG,QAAQ,KAAK,IAAI,CAAC;IAClE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;IAC/B,4DAA4D;IAC5D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,2EAA2E;IAC3E,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3C;AAkJD,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,GAAG,YAAY,CA8F7E"}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { watch, readFileSync, existsSync, statSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { join, relative, extname, dirname } from 'node:path';
|
|
3
|
+
import { parseFrontmatter, parseEntryFromMarkdown } from './frontmatter.js';
|
|
4
|
+
import { indexEntry } from './index.js';
|
|
5
|
+
import { categoryFor, defaultTierFor } from './categories.js';
|
|
6
|
+
import { dirToKind } from './files.js';
|
|
7
|
+
import { shouldIndex } from './indexing.js';
|
|
8
|
+
const EXCLUDED_DIRS = new Set(['_archive', 'projects']);
|
|
9
|
+
const SELF_WRITE_TTL_MS = 2_000;
|
|
10
|
+
const LOCK_STALE_MS = 60_000;
|
|
11
|
+
function isExcluded(relPath) {
|
|
12
|
+
if (relPath.startsWith('.'))
|
|
13
|
+
return true;
|
|
14
|
+
const parts = relPath.split('/');
|
|
15
|
+
for (const part of parts) {
|
|
16
|
+
if (part.startsWith('.'))
|
|
17
|
+
return true;
|
|
18
|
+
if (EXCLUDED_DIRS.has(part))
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Acquire a watcher lock file so only one instance watches per vault.
|
|
25
|
+
* Returns a release function, or null if another instance holds the lock.
|
|
26
|
+
*/
|
|
27
|
+
function acquireWatcherLock(dataDir) {
|
|
28
|
+
const lockPath = join(dataDir, 'watcher.lock');
|
|
29
|
+
mkdirSync(dataDir, { recursive: true });
|
|
30
|
+
if (existsSync(lockPath)) {
|
|
31
|
+
try {
|
|
32
|
+
const content = readFileSync(lockPath, 'utf-8').trim();
|
|
33
|
+
const [pidStr, tsStr] = content.split(':');
|
|
34
|
+
const pid = parseInt(pidStr, 10);
|
|
35
|
+
const ts = parseInt(tsStr, 10);
|
|
36
|
+
// Check if the lock holder is still alive
|
|
37
|
+
if (pid && !isNaN(pid)) {
|
|
38
|
+
try {
|
|
39
|
+
process.kill(pid, 0); // signal 0 = check if alive
|
|
40
|
+
// Process is alive. Check if lock is stale (>60s without refresh).
|
|
41
|
+
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
42
|
+
return null; // another live instance holds the lock
|
|
43
|
+
}
|
|
44
|
+
// Stale lock from a live process that stopped refreshing. Take over.
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Process is dead. Safe to take over the lock.
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// Unreadable lock file. Overwrite it.
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const writeLock = () => {
|
|
56
|
+
try {
|
|
57
|
+
writeFileSync(lockPath, `${process.pid}:${Date.now()}`);
|
|
58
|
+
}
|
|
59
|
+
catch { }
|
|
60
|
+
};
|
|
61
|
+
writeLock();
|
|
62
|
+
// Refresh lock periodically so other instances know we're alive
|
|
63
|
+
const refreshInterval = setInterval(writeLock, 15_000);
|
|
64
|
+
refreshInterval.unref();
|
|
65
|
+
return () => {
|
|
66
|
+
clearInterval(refreshInterval);
|
|
67
|
+
try {
|
|
68
|
+
unlinkSync(lockPath);
|
|
69
|
+
}
|
|
70
|
+
catch { }
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
async function processFile(ctx, filePath, opts) {
|
|
74
|
+
try {
|
|
75
|
+
if (!existsSync(filePath))
|
|
76
|
+
return;
|
|
77
|
+
const stat = statSync(filePath);
|
|
78
|
+
if (!stat.isFile())
|
|
79
|
+
return;
|
|
80
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
81
|
+
const { meta: fmMeta, body: rawBody } = parseFrontmatter(content);
|
|
82
|
+
const id = fmMeta.id;
|
|
83
|
+
if (!id)
|
|
84
|
+
return; // no frontmatter id = not a vault entry
|
|
85
|
+
const relPath = relative(opts.vaultDir, filePath);
|
|
86
|
+
const topDir = relPath.split('/')[0];
|
|
87
|
+
const kind = fmMeta.kind || dirToKind(topDir) || 'reference';
|
|
88
|
+
const category = categoryFor(kind);
|
|
89
|
+
const tier = fmMeta.tier || defaultTierFor(kind);
|
|
90
|
+
const { title, body, meta } = parseEntryFromMarkdown(kind, rawBody, fmMeta);
|
|
91
|
+
const tags = Array.isArray(fmMeta.tags) ? fmMeta.tags : null;
|
|
92
|
+
const source = typeof fmMeta.source === 'string' ? fmMeta.source : null;
|
|
93
|
+
const identity_key = typeof fmMeta.identity_key === 'string' ? fmMeta.identity_key : null;
|
|
94
|
+
const expires_at = typeof fmMeta.expires_at === 'string' ? fmMeta.expires_at : null;
|
|
95
|
+
const createdAt = typeof fmMeta.created === 'string' ? fmMeta.created : new Date().toISOString();
|
|
96
|
+
const source_files = fmMeta.source_files
|
|
97
|
+
? fmMeta.source_files
|
|
98
|
+
: null;
|
|
99
|
+
const explicitIndexed = fmMeta.indexed != null ? fmMeta.indexed === true || fmMeta.indexed === 'true' : undefined;
|
|
100
|
+
const indexed = shouldIndex({ kind, category, bodyLength: body.length, explicitIndexed }, opts.indexingConfig);
|
|
101
|
+
const supersedes = Array.isArray(fmMeta.supersedes) ? fmMeta.supersedes : null;
|
|
102
|
+
const related_to = Array.isArray(fmMeta.related_to) ? fmMeta.related_to : null;
|
|
103
|
+
await indexEntry(ctx, {
|
|
104
|
+
id,
|
|
105
|
+
kind,
|
|
106
|
+
category,
|
|
107
|
+
title,
|
|
108
|
+
body,
|
|
109
|
+
meta: meta || undefined,
|
|
110
|
+
tags,
|
|
111
|
+
source,
|
|
112
|
+
filePath,
|
|
113
|
+
createdAt,
|
|
114
|
+
identity_key,
|
|
115
|
+
expires_at,
|
|
116
|
+
source_files,
|
|
117
|
+
tier,
|
|
118
|
+
indexed,
|
|
119
|
+
supersedes,
|
|
120
|
+
related_to,
|
|
121
|
+
});
|
|
122
|
+
opts.onIndex?.(filePath, 'upsert');
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
opts.onError?.(err);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function processDelete(ctx, filePath, opts) {
|
|
129
|
+
try {
|
|
130
|
+
const row = ctx.db.prepare('SELECT rowid, id FROM vault WHERE file_path = ?').get(filePath);
|
|
131
|
+
if (!row)
|
|
132
|
+
return;
|
|
133
|
+
ctx.deleteVec(row.rowid);
|
|
134
|
+
ctx.deleteCtxVec(row.rowid);
|
|
135
|
+
ctx.stmts.deleteEntry.run(row.id);
|
|
136
|
+
opts.onIndex?.(filePath, 'delete');
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
opts.onError?.(err);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export function startWatcher(ctx, opts) {
|
|
143
|
+
const debounceMs = opts.debounceMs ?? 500;
|
|
144
|
+
const maxConcurrency = opts.maxConcurrency ?? 3;
|
|
145
|
+
const maxQueueSize = opts.maxQueueSize ?? 200;
|
|
146
|
+
// Singleton lock: only one watcher per vault directory
|
|
147
|
+
const dataDir = opts.dataDir || dirname(opts.vaultDir);
|
|
148
|
+
const releaseLock = acquireWatcherLock(dataDir);
|
|
149
|
+
if (!releaseLock) {
|
|
150
|
+
throw new Error('Another instance is already watching this vault. Skipping watcher.');
|
|
151
|
+
}
|
|
152
|
+
const pending = new Map();
|
|
153
|
+
const selfWrites = new Map(); // path -> expiry timestamp
|
|
154
|
+
let activeOps = 0;
|
|
155
|
+
const queue = [];
|
|
156
|
+
let watcher;
|
|
157
|
+
function drainQueue() {
|
|
158
|
+
while (activeOps < maxConcurrency && queue.length > 0) {
|
|
159
|
+
const item = queue.shift();
|
|
160
|
+
activeOps++;
|
|
161
|
+
if (item.isDelete) {
|
|
162
|
+
processDelete(ctx, item.fullPath, opts);
|
|
163
|
+
activeOps--;
|
|
164
|
+
drainQueue();
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
processFile(ctx, item.fullPath, opts)
|
|
168
|
+
.finally(() => {
|
|
169
|
+
activeOps--;
|
|
170
|
+
drainQueue();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function enqueue(fullPath, isDelete) {
|
|
176
|
+
// Drop oldest if queue is full (back-pressure under bulk operations)
|
|
177
|
+
if (queue.length >= maxQueueSize) {
|
|
178
|
+
const dropped = queue.length - maxQueueSize + 1;
|
|
179
|
+
queue.splice(0, dropped);
|
|
180
|
+
}
|
|
181
|
+
queue.push({ fullPath, isDelete });
|
|
182
|
+
drainQueue();
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
watcher = watch(opts.vaultDir, { recursive: true }, (eventType, filename) => {
|
|
186
|
+
if (!filename)
|
|
187
|
+
return;
|
|
188
|
+
const relPath = filename.replace(/\\/g, '/');
|
|
189
|
+
if (extname(relPath) !== '.md')
|
|
190
|
+
return;
|
|
191
|
+
if (isExcluded(relPath))
|
|
192
|
+
return;
|
|
193
|
+
const fullPath = join(opts.vaultDir, relPath);
|
|
194
|
+
// Skip self-written files (written by this MCP server via save_context)
|
|
195
|
+
const selfExpiry = selfWrites.get(fullPath);
|
|
196
|
+
if (selfExpiry && Date.now() < selfExpiry) {
|
|
197
|
+
selfWrites.delete(fullPath);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (pending.has(fullPath))
|
|
201
|
+
clearTimeout(pending.get(fullPath));
|
|
202
|
+
pending.set(fullPath, setTimeout(() => {
|
|
203
|
+
pending.delete(fullPath);
|
|
204
|
+
const isDelete = !existsSync(fullPath);
|
|
205
|
+
enqueue(fullPath, isDelete);
|
|
206
|
+
}, debounceMs));
|
|
207
|
+
});
|
|
208
|
+
watcher.on('error', (err) => {
|
|
209
|
+
opts.onError?.(err);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
releaseLock();
|
|
214
|
+
throw new Error(`Failed to start vault watcher: ${err.message}`);
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
close() {
|
|
218
|
+
for (const timer of pending.values())
|
|
219
|
+
clearTimeout(timer);
|
|
220
|
+
pending.clear();
|
|
221
|
+
queue.length = 0;
|
|
222
|
+
watcher.close();
|
|
223
|
+
releaseLock();
|
|
224
|
+
},
|
|
225
|
+
markSelfWrite(filePath) {
|
|
226
|
+
selfWrites.set(filePath, Date.now() + SELF_WRITE_TTL_MS);
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@context-vault/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.16.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Pure local engine: capture, index, search, and utilities for context-vault",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -66,9 +66,21 @@
|
|
|
66
66
|
"types": "./dist/context.d.ts",
|
|
67
67
|
"import": "./dist/context.js"
|
|
68
68
|
},
|
|
69
|
+
"./compact": {
|
|
70
|
+
"types": "./dist/compact.d.ts",
|
|
71
|
+
"import": "./dist/compact.js"
|
|
72
|
+
},
|
|
69
73
|
"./indexing": {
|
|
70
74
|
"types": "./dist/indexing.d.ts",
|
|
71
75
|
"import": "./dist/indexing.js"
|
|
76
|
+
},
|
|
77
|
+
"./tier-analysis": {
|
|
78
|
+
"types": "./dist/tier-analysis.d.ts",
|
|
79
|
+
"import": "./dist/tier-analysis.js"
|
|
80
|
+
},
|
|
81
|
+
"./watch": {
|
|
82
|
+
"types": "./dist/watch.d.ts",
|
|
83
|
+
"import": "./dist/watch.js"
|
|
72
84
|
}
|
|
73
85
|
},
|
|
74
86
|
"files": [
|
|
@@ -296,6 +296,10 @@ export async function captureAndIndex(
|
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
const entry = writeEntry(ctx, data);
|
|
299
|
+
// Tell the watcher to skip this file (we just wrote and indexed it ourselves)
|
|
300
|
+
if (typeof (ctx as any).markSelfWrite === 'function') {
|
|
301
|
+
(ctx as any).markSelfWrite(entry.filePath);
|
|
302
|
+
}
|
|
299
303
|
try {
|
|
300
304
|
await indexEntry(ctx, entry, precomputedEmbedding);
|
|
301
305
|
if (entry.supersedes?.length && ctx.stmts.updateSupersededBy) {
|
|
@@ -20,6 +20,14 @@ const KIND_CATEGORY: Record<string, string> = {
|
|
|
20
20
|
log: 'event',
|
|
21
21
|
feedback: 'event',
|
|
22
22
|
inbox: 'event',
|
|
23
|
+
events: 'event',
|
|
24
|
+
activity: 'event',
|
|
25
|
+
'user-prompts': 'event',
|
|
26
|
+
agent: 'event',
|
|
27
|
+
handoff: 'event',
|
|
28
|
+
outcome: 'event',
|
|
29
|
+
'session-review': 'event',
|
|
30
|
+
'session-summary': 'event',
|
|
23
31
|
};
|
|
24
32
|
|
|
25
33
|
const CATEGORY_DIR_NAMES: Record<string, string> = {
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { gzipSync, gunzipSync } from 'node:zlib';
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
5
|
+
import type { VaultConfig, PreparedStatements, VaultEntry } from './types.js';
|
|
6
|
+
import { computeHeatForEntry } from './search.js';
|
|
7
|
+
|
|
8
|
+
export interface CompactCtx {
|
|
9
|
+
db: DatabaseSync;
|
|
10
|
+
config: VaultConfig;
|
|
11
|
+
stmts: PreparedStatements;
|
|
12
|
+
deleteVec: (rowid: number) => void;
|
|
13
|
+
deleteCtxVec: (rowid: number) => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface CompactOptions {
|
|
17
|
+
dryRun?: boolean;
|
|
18
|
+
tier?: 'cold';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface CompactResult {
|
|
22
|
+
candidates: number;
|
|
23
|
+
compacted: number;
|
|
24
|
+
bytesReclaimed: number;
|
|
25
|
+
entries: Array<{
|
|
26
|
+
id: string;
|
|
27
|
+
kind: string;
|
|
28
|
+
title: string | null;
|
|
29
|
+
bodySize: number;
|
|
30
|
+
heat: number;
|
|
31
|
+
tier: string | null;
|
|
32
|
+
ageDays: number;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function archiveGzPath(vaultDir: string, id: string): string {
|
|
37
|
+
return join(vaultDir, '_archive', `${id}.md.gz`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function ensureArchiveDir(vaultDir: string): void {
|
|
41
|
+
const dir = join(vaultDir, '_archive');
|
|
42
|
+
if (!existsSync(dir)) {
|
|
43
|
+
mkdirSync(dir, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function summarizeBody(body: string): string {
|
|
48
|
+
if (body.length <= 500) return body;
|
|
49
|
+
return body.slice(0, 500) + '\n\n[compacted: full body archived]';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Find entries eligible for compaction.
|
|
54
|
+
*
|
|
55
|
+
* Default: heat_tier IS NULL or 'cold', age > 90 days, recall_count = 0
|
|
56
|
+
* With tier='cold': also compact cold entries > 30 days
|
|
57
|
+
*/
|
|
58
|
+
function findCompactCandidates(
|
|
59
|
+
db: DatabaseSync,
|
|
60
|
+
options: CompactOptions
|
|
61
|
+
): Array<VaultEntry & { ageDays: number; heat: number; computedTier: string | null }> {
|
|
62
|
+
const now = Date.now();
|
|
63
|
+
|
|
64
|
+
// Query entries that might be eligible: no recalls, old enough
|
|
65
|
+
const minAgeDays = options.tier === 'cold' ? 30 : 90;
|
|
66
|
+
const cutoff = new Date(now - minAgeDays * 86400000).toISOString();
|
|
67
|
+
|
|
68
|
+
const rows = db
|
|
69
|
+
.prepare(
|
|
70
|
+
`SELECT * FROM vault
|
|
71
|
+
WHERE recall_count = 0
|
|
72
|
+
AND created_at <= ?
|
|
73
|
+
AND indexed != 0
|
|
74
|
+
ORDER BY created_at ASC`
|
|
75
|
+
)
|
|
76
|
+
.all(cutoff) as unknown as VaultEntry[];
|
|
77
|
+
|
|
78
|
+
const candidates: Array<VaultEntry & { ageDays: number; heat: number; computedTier: string | null }> = [];
|
|
79
|
+
|
|
80
|
+
for (const row of rows) {
|
|
81
|
+
const { heat, tier: computedTier } = computeHeatForEntry(row);
|
|
82
|
+
|
|
83
|
+
// Default mode: only null or cold heat_tier
|
|
84
|
+
// With --tier cold: also include cold entries specifically
|
|
85
|
+
const eligible =
|
|
86
|
+
options.tier === 'cold'
|
|
87
|
+
? computedTier === 'cold' || computedTier === null
|
|
88
|
+
: computedTier === null || computedTier === 'cold';
|
|
89
|
+
|
|
90
|
+
if (!eligible) continue;
|
|
91
|
+
|
|
92
|
+
const ageDays = Math.floor((now - new Date(row.created_at).getTime()) / 86400000);
|
|
93
|
+
candidates.push({ ...row, ageDays, heat, computedTier });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return candidates;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Compact frozen vault entries: gzip full body to _archive, replace with summary,
|
|
101
|
+
* drop embeddings and mark as unindexed.
|
|
102
|
+
*/
|
|
103
|
+
export async function compact(
|
|
104
|
+
ctx: CompactCtx,
|
|
105
|
+
options: CompactOptions = {}
|
|
106
|
+
): Promise<CompactResult> {
|
|
107
|
+
const candidates = findCompactCandidates(ctx.db, options);
|
|
108
|
+
|
|
109
|
+
const result: CompactResult = {
|
|
110
|
+
candidates: candidates.length,
|
|
111
|
+
compacted: 0,
|
|
112
|
+
bytesReclaimed: 0,
|
|
113
|
+
entries: [],
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
if (candidates.length === 0 || options.dryRun) {
|
|
117
|
+
result.entries = candidates.map((c) => ({
|
|
118
|
+
id: c.id,
|
|
119
|
+
kind: c.kind,
|
|
120
|
+
title: c.title,
|
|
121
|
+
bodySize: Buffer.byteLength(c.body, 'utf-8'),
|
|
122
|
+
heat: c.heat,
|
|
123
|
+
tier: c.computedTier,
|
|
124
|
+
ageDays: c.ageDays,
|
|
125
|
+
}));
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
ensureArchiveDir(ctx.config.vaultDir);
|
|
130
|
+
|
|
131
|
+
for (const entry of candidates) {
|
|
132
|
+
const bodyBytes = Buffer.byteLength(entry.body, 'utf-8');
|
|
133
|
+
const gzPath = archiveGzPath(ctx.config.vaultDir, entry.id);
|
|
134
|
+
|
|
135
|
+
// Gzip and write the full body
|
|
136
|
+
const compressed = gzipSync(Buffer.from(entry.body, 'utf-8'));
|
|
137
|
+
writeFileSync(gzPath, compressed);
|
|
138
|
+
|
|
139
|
+
// Replace body with summary
|
|
140
|
+
const summary = summarizeBody(entry.body);
|
|
141
|
+
|
|
142
|
+
// Drop embeddings
|
|
143
|
+
const rowidRow = ctx.stmts.getRowid.get(entry.id) as { rowid?: number } | undefined;
|
|
144
|
+
if (rowidRow?.rowid) {
|
|
145
|
+
try { ctx.deleteVec(Number(rowidRow.rowid)); } catch {}
|
|
146
|
+
try { ctx.deleteCtxVec(Number(rowidRow.rowid)); } catch {}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Update the DB entry: set indexed=0, update body
|
|
150
|
+
ctx.db
|
|
151
|
+
.prepare(
|
|
152
|
+
`UPDATE vault SET body = ?, indexed = 0, updated_at = ? WHERE id = ?`
|
|
153
|
+
)
|
|
154
|
+
.run(summary, new Date().toISOString(), entry.id);
|
|
155
|
+
|
|
156
|
+
const summaryBytes = Buffer.byteLength(summary, 'utf-8');
|
|
157
|
+
result.bytesReclaimed += bodyBytes - summaryBytes;
|
|
158
|
+
result.compacted++;
|
|
159
|
+
result.entries.push({
|
|
160
|
+
id: entry.id,
|
|
161
|
+
kind: entry.kind,
|
|
162
|
+
title: entry.title,
|
|
163
|
+
bodySize: bodyBytes,
|
|
164
|
+
heat: entry.heat,
|
|
165
|
+
tier: entry.computedTier,
|
|
166
|
+
ageDays: entry.ageDays,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Restore a compacted entry's full body from the gzipped archive.
|
|
175
|
+
* Returns the decompressed body or null if no archive exists.
|
|
176
|
+
*/
|
|
177
|
+
export function restoreCompactedBody(vaultDir: string, id: string): string | null {
|
|
178
|
+
const gzPath = archiveGzPath(vaultDir, id);
|
|
179
|
+
if (!existsSync(gzPath)) return null;
|
|
180
|
+
|
|
181
|
+
const compressed = readFileSync(gzPath);
|
|
182
|
+
return gunzipSync(compressed).toString('utf-8');
|
|
183
|
+
}
|
|
@@ -73,6 +73,7 @@ export function resolveConfig(): VaultConfig {
|
|
|
73
73
|
lifecycle: structuredClone(DEFAULT_LIFECYCLE),
|
|
74
74
|
autoInsights: { ...DEFAULT_AUTO_INSIGHTS },
|
|
75
75
|
indexing: { ...DEFAULT_INDEXING },
|
|
76
|
+
watch: { enabled: false },
|
|
76
77
|
};
|
|
77
78
|
|
|
78
79
|
const configPath = join(dataDir, 'config.json');
|
|
@@ -162,6 +163,13 @@ export function resolveConfig(): VaultConfig {
|
|
|
162
163
|
if (ix.maxBodySize != null) config.indexing.maxBodySize = Number(ix.maxBodySize);
|
|
163
164
|
if (ix.autoIndexEvents != null) config.indexing.autoIndexEvents = ix.autoIndexEvents === true;
|
|
164
165
|
}
|
|
166
|
+
if (fc.watch && typeof fc.watch === 'object') {
|
|
167
|
+
const w = fc.watch;
|
|
168
|
+
if (!config.watch) config.watch = { enabled: true };
|
|
169
|
+
if (w.enabled != null) config.watch.enabled = w.enabled === true;
|
|
170
|
+
if (typeof w.path === 'string') config.watch.path = w.path;
|
|
171
|
+
if (w.debounceMs != null) config.watch.debounceMs = Number(w.debounceMs);
|
|
172
|
+
}
|
|
165
173
|
if (fc.remote && typeof fc.remote === 'object') {
|
|
166
174
|
const r = fc.remote;
|
|
167
175
|
config.remote = {
|
|
@@ -147,7 +147,8 @@ export const SCHEMA_DDL = `
|
|
|
147
147
|
indexed INTEGER DEFAULT 1,
|
|
148
148
|
recall_count INTEGER DEFAULT 0,
|
|
149
149
|
recall_sessions INTEGER DEFAULT 0,
|
|
150
|
-
last_recalled_at TEXT
|
|
150
|
+
last_recalled_at TEXT,
|
|
151
|
+
heat_tier TEXT CHECK(heat_tier IN ('hot', 'warm', 'cold'))
|
|
151
152
|
);
|
|
152
153
|
|
|
153
154
|
CREATE INDEX IF NOT EXISTS idx_vault_kind ON vault(kind);
|
|
@@ -158,6 +159,7 @@ export const SCHEMA_DDL = `
|
|
|
158
159
|
CREATE INDEX IF NOT EXISTS idx_vault_superseded ON vault(superseded_by) WHERE superseded_by IS NOT NULL;
|
|
159
160
|
CREATE INDEX IF NOT EXISTS idx_vault_tier ON vault(tier);
|
|
160
161
|
CREATE INDEX IF NOT EXISTS idx_vault_indexed ON vault(indexed);
|
|
162
|
+
CREATE INDEX IF NOT EXISTS idx_vault_heat_tier ON vault(heat_tier) WHERE heat_tier IS NOT NULL;
|
|
161
163
|
|
|
162
164
|
CREATE VIRTUAL TABLE IF NOT EXISTS vault_fts USING fts5(
|
|
163
165
|
title, body, tags, kind,
|
|
@@ -190,9 +192,20 @@ export const SCHEMA_DDL = `
|
|
|
190
192
|
last_at TEXT NOT NULL,
|
|
191
193
|
PRIMARY KEY (entry_a, entry_b)
|
|
192
194
|
);
|
|
195
|
+
|
|
196
|
+
CREATE TABLE IF NOT EXISTS access_log (
|
|
197
|
+
id INTEGER PRIMARY KEY,
|
|
198
|
+
entry_id TEXT NOT NULL,
|
|
199
|
+
query TEXT,
|
|
200
|
+
session_id TEXT,
|
|
201
|
+
session_goal TEXT,
|
|
202
|
+
accessed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
203
|
+
);
|
|
204
|
+
CREATE INDEX IF NOT EXISTS idx_access_log_entry_at ON access_log(entry_id, accessed_at);
|
|
205
|
+
CREATE INDEX IF NOT EXISTS idx_access_log_goal ON access_log(session_goal) WHERE session_goal IS NOT NULL;
|
|
193
206
|
`;
|
|
194
207
|
|
|
195
|
-
const CURRENT_VERSION =
|
|
208
|
+
const CURRENT_VERSION = 19;
|
|
196
209
|
|
|
197
210
|
export async function initDatabase(dbPath: string): Promise<DatabaseSync> {
|
|
198
211
|
const sqliteVec = await loadSqliteVec();
|
|
@@ -272,9 +285,32 @@ export async function initDatabase(dbPath: string): Promise<DatabaseSync> {
|
|
|
272
285
|
last_at TEXT NOT NULL,
|
|
273
286
|
PRIMARY KEY (entry_a, entry_b)
|
|
274
287
|
)`);
|
|
275
|
-
db.exec(`PRAGMA user_version =
|
|
288
|
+
db.exec(`PRAGMA user_version = 18`);
|
|
276
289
|
} catch (e) {
|
|
277
290
|
console.error(`[context-vault] v17->v18 migration failed: ${(e as Error).message}`);
|
|
291
|
+
return db;
|
|
292
|
+
}
|
|
293
|
+
// Fall through to v18->v19 migration
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// v18 -> v19: add access_log table and heat_tier column
|
|
297
|
+
if (version === 18 || version === 17 || version === 16 || version === 15) {
|
|
298
|
+
try {
|
|
299
|
+
db.exec(`CREATE TABLE IF NOT EXISTS access_log (
|
|
300
|
+
id INTEGER PRIMARY KEY,
|
|
301
|
+
entry_id TEXT NOT NULL,
|
|
302
|
+
query TEXT,
|
|
303
|
+
session_id TEXT,
|
|
304
|
+
session_goal TEXT,
|
|
305
|
+
accessed_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
306
|
+
)`);
|
|
307
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_access_log_entry_at ON access_log(entry_id, accessed_at)`);
|
|
308
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_access_log_goal ON access_log(session_goal) WHERE session_goal IS NOT NULL`);
|
|
309
|
+
db.exec(`ALTER TABLE vault ADD COLUMN heat_tier TEXT CHECK(heat_tier IN ('hot', 'warm', 'cold'))`);
|
|
310
|
+
db.exec(`CREATE INDEX IF NOT EXISTS idx_vault_heat_tier ON vault(heat_tier) WHERE heat_tier IS NOT NULL`);
|
|
311
|
+
db.exec(`PRAGMA user_version = ${CURRENT_VERSION}`);
|
|
312
|
+
} catch (e) {
|
|
313
|
+
console.error(`[context-vault] v18->v19 migration failed: ${(e as Error).message}`);
|
|
278
314
|
}
|
|
279
315
|
return db;
|
|
280
316
|
}
|
|
@@ -320,7 +356,7 @@ export async function initDatabase(dbPath: string): Promise<DatabaseSync> {
|
|
|
320
356
|
return freshDb;
|
|
321
357
|
}
|
|
322
358
|
|
|
323
|
-
if (version <
|
|
359
|
+
if (version < 19) {
|
|
324
360
|
db.exec(SCHEMA_DDL);
|
|
325
361
|
db.exec(`PRAGMA user_version = ${CURRENT_VERSION}`);
|
|
326
362
|
}
|