@context-vault/core 3.1.6 → 3.1.7
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/dist/capture.d.ts +1 -1
- package/dist/capture.d.ts.map +1 -1
- package/dist/capture.js +34 -47
- package/dist/capture.js.map +1 -1
- package/dist/categories.js +30 -30
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +37 -43
- package/dist/config.js.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +4 -4
- package/dist/constants.js.map +1 -1
- package/dist/db.d.ts +2 -2
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +21 -20
- package/dist/db.js.map +1 -1
- package/dist/embed.d.ts.map +1 -1
- package/dist/embed.js +11 -11
- package/dist/embed.js.map +1 -1
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +12 -13
- package/dist/files.js.map +1 -1
- package/dist/formatters.js +5 -5
- package/dist/frontmatter.d.ts.map +1 -1
- package/dist/frontmatter.js +23 -23
- package/dist/frontmatter.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +58 -46
- package/dist/index.js.map +1 -1
- package/dist/ingest-url.d.ts.map +1 -1
- package/dist/ingest-url.js +30 -33
- package/dist/ingest-url.js.map +1 -1
- package/dist/main.d.ts +13 -13
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +12 -12
- package/dist/main.js.map +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +20 -22
- package/dist/search.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +1 -1
- package/src/capture.ts +44 -81
- package/src/categories.ts +30 -30
- package/src/config.ts +45 -60
- package/src/constants.ts +8 -10
- package/src/db.ts +37 -56
- package/src/embed.ts +15 -26
- package/src/files.ts +13 -16
- package/src/formatters.ts +5 -5
- package/src/frontmatter.ts +26 -30
- package/src/index.ts +94 -100
- package/src/ingest-url.ts +56 -93
- package/src/main.ts +13 -18
- package/src/search.ts +34 -56
- package/src/types.ts +1 -1
package/dist/search.js
CHANGED
|
@@ -15,19 +15,19 @@ export function dotProduct(a, b) {
|
|
|
15
15
|
export function buildFtsQuery(query) {
|
|
16
16
|
const words = query
|
|
17
17
|
.split(/[\s-]+/)
|
|
18
|
-
.map((w) => w.replace(/[*"():^~{}]/g,
|
|
18
|
+
.map((w) => w.replace(/[*"():^~{}]/g, ''))
|
|
19
19
|
.filter((w) => w.length > 0);
|
|
20
20
|
if (!words.length)
|
|
21
21
|
return null;
|
|
22
22
|
if (words.length === 1)
|
|
23
23
|
return `"${words[0]}"`;
|
|
24
|
-
const phrase = `"${words.join(
|
|
25
|
-
const near = `NEAR(${words.map((w) => `"${w}"`).join(
|
|
26
|
-
const and = words.map((w) => `"${w}"`).join(
|
|
24
|
+
const phrase = `"${words.join(' ')}"`;
|
|
25
|
+
const near = `NEAR(${words.map((w) => `"${w}"`).join(' ')}, 10)`;
|
|
26
|
+
const and = words.map((w) => `"${w}"`).join(' AND ');
|
|
27
27
|
return `${phrase} OR ${near} OR ${and}`;
|
|
28
28
|
}
|
|
29
29
|
export function recencyBoost(createdAt, category, decayDays = 30) {
|
|
30
|
-
if (category !==
|
|
30
|
+
if (category !== 'event')
|
|
31
31
|
return 1.0;
|
|
32
32
|
const ageDays = (Date.now() - new Date(createdAt).getTime()) / 86400000;
|
|
33
33
|
return 1 / (1 + ageDays / decayDays);
|
|
@@ -36,23 +36,23 @@ export function buildFilterClauses({ categoryFilter, excludeEvents = false, sinc
|
|
|
36
36
|
const clauses = [];
|
|
37
37
|
const params = [];
|
|
38
38
|
if (categoryFilter) {
|
|
39
|
-
clauses.push(
|
|
39
|
+
clauses.push('e.category = ?');
|
|
40
40
|
params.push(categoryFilter);
|
|
41
41
|
}
|
|
42
42
|
if (excludeEvents && !categoryFilter) {
|
|
43
43
|
clauses.push("e.category != 'event'");
|
|
44
44
|
}
|
|
45
45
|
if (since) {
|
|
46
|
-
clauses.push(
|
|
46
|
+
clauses.push('e.created_at >= ?');
|
|
47
47
|
params.push(since);
|
|
48
48
|
}
|
|
49
49
|
if (until) {
|
|
50
|
-
clauses.push(
|
|
50
|
+
clauses.push('e.created_at <= ?');
|
|
51
51
|
params.push(until);
|
|
52
52
|
}
|
|
53
53
|
clauses.push("(e.expires_at IS NULL OR e.expires_at > datetime('now'))");
|
|
54
54
|
if (!includeSuperseeded) {
|
|
55
|
-
clauses.push(
|
|
55
|
+
clauses.push('e.superseded_by IS NULL');
|
|
56
56
|
}
|
|
57
57
|
return { clauses, params };
|
|
58
58
|
}
|
|
@@ -82,18 +82,16 @@ export async function hybridSearch(ctx, query, opts = {}) {
|
|
|
82
82
|
const ftsQuery = buildFtsQuery(query);
|
|
83
83
|
if (ftsQuery) {
|
|
84
84
|
try {
|
|
85
|
-
const whereParts = [
|
|
85
|
+
const whereParts = ['vault_fts MATCH ?'];
|
|
86
86
|
const ftsParams = [ftsQuery];
|
|
87
87
|
if (kindFilter) {
|
|
88
|
-
whereParts.push(
|
|
88
|
+
whereParts.push('e.kind = ?');
|
|
89
89
|
ftsParams.push(kindFilter);
|
|
90
90
|
}
|
|
91
91
|
whereParts.push(...extraFilters.clauses);
|
|
92
92
|
ftsParams.push(...extraFilters.params);
|
|
93
|
-
const ftsSQL = `SELECT e.*, rank FROM vault_fts f JOIN vault e ON f.rowid = e.rowid WHERE ${whereParts.join(
|
|
94
|
-
const rows = ctx.db
|
|
95
|
-
.prepare(ftsSQL)
|
|
96
|
-
.all(...ftsParams);
|
|
93
|
+
const ftsSQL = `SELECT e.*, rank FROM vault_fts f JOIN vault e ON f.rowid = e.rowid WHERE ${whereParts.join(' AND ')} ORDER BY rank LIMIT 15`;
|
|
94
|
+
const rows = ctx.db.prepare(ftsSQL).all(...ftsParams);
|
|
97
95
|
for (const { rank: _rank, ...row } of rows) {
|
|
98
96
|
ftsRankedIds.push(row.id);
|
|
99
97
|
if (!rowMap.has(row.id))
|
|
@@ -101,7 +99,7 @@ export async function hybridSearch(ctx, query, opts = {}) {
|
|
|
101
99
|
}
|
|
102
100
|
}
|
|
103
101
|
catch (err) {
|
|
104
|
-
if (!err.message?.includes(
|
|
102
|
+
if (!err.message?.includes('fts5: syntax error')) {
|
|
105
103
|
console.error(`[retrieve] FTS search error: ${err.message}`);
|
|
106
104
|
}
|
|
107
105
|
}
|
|
@@ -109,7 +107,7 @@ export async function hybridSearch(ctx, query, opts = {}) {
|
|
|
109
107
|
const vecRankedIds = [];
|
|
110
108
|
const vecSimMap = new Map();
|
|
111
109
|
try {
|
|
112
|
-
const vecCount = ctx.db.prepare(
|
|
110
|
+
const vecCount = ctx.db.prepare('SELECT COUNT(*) as c FROM vault_vec').get().c;
|
|
113
111
|
if (vecCount > 0) {
|
|
114
112
|
queryVec = await ctx.embed(query);
|
|
115
113
|
if (queryVec) {
|
|
@@ -119,7 +117,7 @@ export async function hybridSearch(ctx, query, opts = {}) {
|
|
|
119
117
|
.all(queryVec, vecLimit);
|
|
120
118
|
if (vecRows.length) {
|
|
121
119
|
const rowids = vecRows.map((vr) => vr.rowid);
|
|
122
|
-
const placeholders = rowids.map(() =>
|
|
120
|
+
const placeholders = rowids.map(() => '?').join(',');
|
|
123
121
|
const hydrated = ctx.db
|
|
124
122
|
.prepare(`SELECT rowid, * FROM vault WHERE rowid IN (${placeholders})`)
|
|
125
123
|
.all(...rowids);
|
|
@@ -134,7 +132,7 @@ export async function hybridSearch(ctx, query, opts = {}) {
|
|
|
134
132
|
continue;
|
|
135
133
|
if (categoryFilter && row.category !== categoryFilter)
|
|
136
134
|
continue;
|
|
137
|
-
if (excludeEvents && row.category ===
|
|
135
|
+
if (excludeEvents && row.category === 'event')
|
|
138
136
|
continue;
|
|
139
137
|
if (since && row.created_at < since)
|
|
140
138
|
continue;
|
|
@@ -155,7 +153,7 @@ export async function hybridSearch(ctx, query, opts = {}) {
|
|
|
155
153
|
}
|
|
156
154
|
}
|
|
157
155
|
catch (err) {
|
|
158
|
-
if (!err.message?.includes(
|
|
156
|
+
if (!err.message?.includes('no such table')) {
|
|
159
157
|
console.error(`[retrieve] Vector search error: ${err.message}`);
|
|
160
158
|
}
|
|
161
159
|
}
|
|
@@ -178,7 +176,7 @@ export async function hybridSearch(ctx, query, opts = {}) {
|
|
|
178
176
|
rowidToId.set(rowid, id);
|
|
179
177
|
const rowidsToFetch = [...idToRowid.values()];
|
|
180
178
|
try {
|
|
181
|
-
const placeholders = rowidsToFetch.map(() =>
|
|
179
|
+
const placeholders = rowidsToFetch.map(() => '?').join(',');
|
|
182
180
|
const vecData = ctx.db
|
|
183
181
|
.prepare(`SELECT rowid, embedding FROM vault_vec WHERE rowid IN (${placeholders})`)
|
|
184
182
|
.all(...rowidsToFetch);
|
|
@@ -227,7 +225,7 @@ function trackAccess(ctx, entries) {
|
|
|
227
225
|
if (!entries.length)
|
|
228
226
|
return;
|
|
229
227
|
try {
|
|
230
|
-
const placeholders = entries.map(() =>
|
|
228
|
+
const placeholders = entries.map(() => '?').join(',');
|
|
231
229
|
ctx.db
|
|
232
230
|
.prepare(`UPDATE vault SET hit_count = hit_count + 1, last_accessed_at = datetime('now') WHERE id IN (${placeholders})`)
|
|
233
231
|
.run(...entries.map((e) => e.id));
|
package/dist/search.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
package/src/capture.ts
CHANGED
|
@@ -1,33 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
} from
|
|
8
|
-
import {
|
|
9
|
-
import { ulid, slugify, kindToPath } from "./files.js";
|
|
10
|
-
import { categoryFor, defaultTierFor } from "./categories.js";
|
|
11
|
-
import { parseFrontmatter, formatFrontmatter } from "./frontmatter.js";
|
|
12
|
-
import { formatBody } from "./formatters.js";
|
|
13
|
-
import type {
|
|
14
|
-
BaseCtx,
|
|
15
|
-
CaptureInput,
|
|
16
|
-
CaptureResult,
|
|
17
|
-
IndexEntryInput,
|
|
18
|
-
} from "./types.js";
|
|
19
|
-
import { indexEntry } from "./index.js";
|
|
1
|
+
import { existsSync, readFileSync, unlinkSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { resolve, relative } from 'node:path';
|
|
3
|
+
import { ulid, slugify, kindToPath } from './files.js';
|
|
4
|
+
import { categoryFor, defaultTierFor } from './categories.js';
|
|
5
|
+
import { parseFrontmatter, formatFrontmatter } from './frontmatter.js';
|
|
6
|
+
import { formatBody } from './formatters.js';
|
|
7
|
+
import type { BaseCtx, CaptureInput, CaptureResult, IndexEntryInput } from './types.js';
|
|
8
|
+
import { indexEntry } from './index.js';
|
|
20
9
|
|
|
21
|
-
function safeFolderPath(
|
|
22
|
-
vaultDir: string,
|
|
23
|
-
kind: string,
|
|
24
|
-
folder?: string | null,
|
|
25
|
-
): string {
|
|
10
|
+
function safeFolderPath(vaultDir: string, kind: string, folder?: string | null): string {
|
|
26
11
|
const base = resolve(vaultDir, kindToPath(kind));
|
|
27
12
|
if (!folder) return base;
|
|
28
13
|
const resolved = resolve(base, folder);
|
|
29
14
|
const rel = relative(base, resolved);
|
|
30
|
-
if (rel.startsWith(
|
|
15
|
+
if (rel.startsWith('..') || resolve(base, rel) !== resolved) {
|
|
31
16
|
throw new Error(`Folder path escapes vault: "${folder}"`);
|
|
32
17
|
}
|
|
33
18
|
return resolved;
|
|
@@ -51,17 +36,15 @@ function writeEntryFile(
|
|
|
51
36
|
expires_at?: string | null;
|
|
52
37
|
supersedes?: string[] | null;
|
|
53
38
|
related_to?: string[] | null;
|
|
54
|
-
}
|
|
39
|
+
}
|
|
55
40
|
): string {
|
|
56
|
-
const resolvedFolder = params.folder || (params.meta?.folder as string) ||
|
|
41
|
+
const resolvedFolder = params.folder || (params.meta?.folder as string) || '';
|
|
57
42
|
const dir = safeFolderPath(vaultDir, kind, resolvedFolder);
|
|
58
43
|
|
|
59
44
|
try {
|
|
60
45
|
mkdirSync(dir, { recursive: true });
|
|
61
46
|
} catch (e) {
|
|
62
|
-
throw new Error(
|
|
63
|
-
`Failed to create directory "${dir}": ${(e as Error).message}`,
|
|
64
|
-
);
|
|
47
|
+
throw new Error(`Failed to create directory "${dir}": ${(e as Error).message}`);
|
|
65
48
|
}
|
|
66
49
|
|
|
67
50
|
const created = params.createdAt || new Date().toISOString();
|
|
@@ -69,7 +52,7 @@ function writeEntryFile(
|
|
|
69
52
|
|
|
70
53
|
if (params.meta) {
|
|
71
54
|
for (const [k, v] of Object.entries(params.meta)) {
|
|
72
|
-
if (k ===
|
|
55
|
+
if (k === 'folder') continue;
|
|
73
56
|
if (v !== null && v !== undefined) fmFields[k] = v;
|
|
74
57
|
}
|
|
75
58
|
}
|
|
@@ -79,10 +62,9 @@ function writeEntryFile(
|
|
|
79
62
|
if (params.supersedes?.length) fmFields.supersedes = params.supersedes;
|
|
80
63
|
if (params.related_to?.length) fmFields.related_to = params.related_to;
|
|
81
64
|
fmFields.tags = params.tags || [];
|
|
82
|
-
fmFields.source = params.source ||
|
|
65
|
+
fmFields.source = params.source || 'claude-code';
|
|
83
66
|
fmFields.created = created;
|
|
84
|
-
if (params.updatedAt && params.updatedAt !== created)
|
|
85
|
-
fmFields.updated = params.updatedAt;
|
|
67
|
+
if (params.updatedAt && params.updatedAt !== created) fmFields.updated = params.updatedAt;
|
|
86
68
|
|
|
87
69
|
const mdBody = formatBody(kind, {
|
|
88
70
|
title: params.title || undefined,
|
|
@@ -91,11 +73,9 @@ function writeEntryFile(
|
|
|
91
73
|
});
|
|
92
74
|
|
|
93
75
|
let filename: string;
|
|
94
|
-
if (params.category ===
|
|
76
|
+
if (params.category === 'entity' && params.identity_key) {
|
|
95
77
|
const identitySlug = slugify(params.identity_key);
|
|
96
|
-
filename = identitySlug
|
|
97
|
-
? `${identitySlug}.md`
|
|
98
|
-
: `${params.id.slice(-8).toLowerCase()}.md`;
|
|
78
|
+
filename = identitySlug ? `${identitySlug}.md` : `${params.id.slice(-8).toLowerCase()}.md`;
|
|
99
79
|
} else {
|
|
100
80
|
const slug = slugify((params.title || params.body).slice(0, 40));
|
|
101
81
|
const shortId = params.id.slice(-8).toLowerCase();
|
|
@@ -108,26 +88,24 @@ function writeEntryFile(
|
|
|
108
88
|
try {
|
|
109
89
|
writeFileSync(filePath, md);
|
|
110
90
|
} catch (e) {
|
|
111
|
-
throw new Error(
|
|
112
|
-
`Failed to write entry file "${filePath}": ${(e as Error).message}`,
|
|
113
|
-
);
|
|
91
|
+
throw new Error(`Failed to write entry file "${filePath}": ${(e as Error).message}`);
|
|
114
92
|
}
|
|
115
93
|
|
|
116
94
|
return filePath;
|
|
117
95
|
}
|
|
118
96
|
|
|
119
97
|
export function writeEntry(ctx: BaseCtx, data: CaptureInput): CaptureResult {
|
|
120
|
-
if (!data.kind || typeof data.kind !==
|
|
121
|
-
throw new Error(
|
|
98
|
+
if (!data.kind || typeof data.kind !== 'string') {
|
|
99
|
+
throw new Error('writeEntry: kind is required (non-empty string)');
|
|
122
100
|
}
|
|
123
|
-
if (!data.body || typeof data.body !==
|
|
124
|
-
throw new Error(
|
|
101
|
+
if (!data.body || typeof data.body !== 'string' || !data.body.trim()) {
|
|
102
|
+
throw new Error('writeEntry: body is required (non-empty string)');
|
|
125
103
|
}
|
|
126
104
|
if (data.tags != null && !Array.isArray(data.tags)) {
|
|
127
|
-
throw new Error(
|
|
105
|
+
throw new Error('writeEntry: tags must be an array if provided');
|
|
128
106
|
}
|
|
129
|
-
if (data.meta != null && typeof data.meta !==
|
|
130
|
-
throw new Error(
|
|
107
|
+
if (data.meta != null && typeof data.meta !== 'object') {
|
|
108
|
+
throw new Error('writeEntry: meta must be an object if provided');
|
|
131
109
|
}
|
|
132
110
|
|
|
133
111
|
const category = categoryFor(data.kind);
|
|
@@ -135,13 +113,13 @@ export function writeEntry(ctx: BaseCtx, data: CaptureInput): CaptureResult {
|
|
|
135
113
|
let id: string;
|
|
136
114
|
let createdAt: string;
|
|
137
115
|
let updatedAt: string;
|
|
138
|
-
if (category ===
|
|
116
|
+
if (category === 'entity' && data.identity_key) {
|
|
139
117
|
const identitySlug = slugify(data.identity_key);
|
|
140
118
|
const dir = resolve(ctx.config.vaultDir, kindToPath(data.kind));
|
|
141
119
|
const existingPath = resolve(dir, `${identitySlug}.md`);
|
|
142
120
|
|
|
143
121
|
if (existsSync(existingPath)) {
|
|
144
|
-
const raw = readFileSync(existingPath,
|
|
122
|
+
const raw = readFileSync(existingPath, 'utf-8');
|
|
145
123
|
const { meta: fmMeta } = parseFrontmatter(raw);
|
|
146
124
|
id = (fmMeta.id as string) || ulid();
|
|
147
125
|
createdAt = (fmMeta.created as string) || new Date().toISOString();
|
|
@@ -208,12 +186,12 @@ export function updateEntryFile(
|
|
|
208
186
|
supersedes?: string[] | null;
|
|
209
187
|
related_to?: string[] | null;
|
|
210
188
|
source_files?: Array<{ path: string; hash: string }> | null;
|
|
211
|
-
}
|
|
189
|
+
}
|
|
212
190
|
): IndexEntryInput & {
|
|
213
191
|
supersedes?: string[] | null;
|
|
214
192
|
related_to?: string[] | null;
|
|
215
193
|
} {
|
|
216
|
-
const raw = readFileSync(existing.file_path as string,
|
|
194
|
+
const raw = readFileSync(existing.file_path as string, 'utf-8');
|
|
217
195
|
const { meta: fmMeta } = parseFrontmatter(raw);
|
|
218
196
|
|
|
219
197
|
const existingMeta = existing.meta ? JSON.parse(existing.meta as string) : {};
|
|
@@ -222,29 +200,15 @@ export function updateEntryFile(
|
|
|
222
200
|
? JSON.parse(existing.related_to as string)
|
|
223
201
|
: (fmMeta.related_to as string[]) || null;
|
|
224
202
|
|
|
225
|
-
const title =
|
|
226
|
-
|
|
227
|
-
? updates.title
|
|
228
|
-
: (existing.title as string | null);
|
|
229
|
-
const body =
|
|
230
|
-
updates.body !== undefined
|
|
231
|
-
? (updates.body as string)
|
|
232
|
-
: (existing.body as string);
|
|
203
|
+
const title = updates.title !== undefined ? updates.title : (existing.title as string | null);
|
|
204
|
+
const body = updates.body !== undefined ? (updates.body as string) : (existing.body as string);
|
|
233
205
|
const tags = updates.tags !== undefined ? updates.tags : existingTags;
|
|
234
|
-
const source =
|
|
235
|
-
updates.source !== undefined
|
|
236
|
-
? updates.source
|
|
237
|
-
: (existing.source as string | null);
|
|
206
|
+
const source = updates.source !== undefined ? updates.source : (existing.source as string | null);
|
|
238
207
|
const expires_at =
|
|
239
|
-
updates.expires_at !== undefined
|
|
240
|
-
? updates.expires_at
|
|
241
|
-
: (existing.expires_at as string | null);
|
|
208
|
+
updates.expires_at !== undefined ? updates.expires_at : (existing.expires_at as string | null);
|
|
242
209
|
const supersedes =
|
|
243
|
-
updates.supersedes !== undefined
|
|
244
|
-
|
|
245
|
-
: (fmMeta.supersedes as string[]) || null;
|
|
246
|
-
const related_to =
|
|
247
|
-
updates.related_to !== undefined ? updates.related_to : existingRelatedTo;
|
|
210
|
+
updates.supersedes !== undefined ? updates.supersedes : (fmMeta.supersedes as string[]) || null;
|
|
211
|
+
const related_to = updates.related_to !== undefined ? updates.related_to : existingRelatedTo;
|
|
248
212
|
const source_files =
|
|
249
213
|
updates.source_files !== undefined
|
|
250
214
|
? updates.source_files
|
|
@@ -262,7 +226,7 @@ export function updateEntryFile(
|
|
|
262
226
|
const now = new Date().toISOString();
|
|
263
227
|
const fmFields: Record<string, unknown> = { id: existing.id };
|
|
264
228
|
for (const [k, v] of Object.entries(mergedMeta)) {
|
|
265
|
-
if (k ===
|
|
229
|
+
if (k === 'folder') continue;
|
|
266
230
|
if (v !== null && v !== undefined) fmFields[k] = v;
|
|
267
231
|
}
|
|
268
232
|
if (existing.identity_key) fmFields.identity_key = existing.identity_key;
|
|
@@ -270,9 +234,8 @@ export function updateEntryFile(
|
|
|
270
234
|
if (supersedes?.length) fmFields.supersedes = supersedes;
|
|
271
235
|
if (related_to?.length) fmFields.related_to = related_to;
|
|
272
236
|
fmFields.tags = tags;
|
|
273
|
-
fmFields.source = source ||
|
|
274
|
-
fmFields.created =
|
|
275
|
-
(fmMeta.created as string) || (existing.created_at as string);
|
|
237
|
+
fmFields.source = source || 'claude-code';
|
|
238
|
+
fmFields.created = (fmMeta.created as string) || (existing.created_at as string);
|
|
276
239
|
if (now !== fmFields.created) fmFields.updated = now;
|
|
277
240
|
|
|
278
241
|
const mdBody = formatBody(existing.kind as string, {
|
|
@@ -309,15 +272,15 @@ export function updateEntryFile(
|
|
|
309
272
|
export async function captureAndIndex(
|
|
310
273
|
ctx: BaseCtx,
|
|
311
274
|
data: CaptureInput,
|
|
312
|
-
precomputedEmbedding?: Float32Array | null
|
|
275
|
+
precomputedEmbedding?: Float32Array | null
|
|
313
276
|
): Promise<CaptureResult> {
|
|
314
277
|
let previousContent: string | null = null;
|
|
315
|
-
if (categoryFor(data.kind) ===
|
|
278
|
+
if (categoryFor(data.kind) === 'entity' && data.identity_key) {
|
|
316
279
|
const identitySlug = slugify(data.identity_key);
|
|
317
280
|
const dir = resolve(ctx.config.vaultDir, kindToPath(data.kind));
|
|
318
281
|
const existingPath = resolve(dir, `${identitySlug}.md`);
|
|
319
282
|
if (existsSync(existingPath)) {
|
|
320
|
-
previousContent = readFileSync(existingPath,
|
|
283
|
+
previousContent = readFileSync(existingPath, 'utf-8');
|
|
321
284
|
}
|
|
322
285
|
}
|
|
323
286
|
|
|
@@ -326,7 +289,7 @@ export async function captureAndIndex(
|
|
|
326
289
|
await indexEntry(ctx, entry, precomputedEmbedding);
|
|
327
290
|
if (entry.supersedes?.length && ctx.stmts.updateSupersededBy) {
|
|
328
291
|
for (const supersededId of entry.supersedes) {
|
|
329
|
-
if (typeof supersededId ===
|
|
292
|
+
if (typeof supersededId === 'string' && supersededId.trim()) {
|
|
330
293
|
ctx.stmts.updateSupersededBy.run(entry.id, supersededId.trim());
|
|
331
294
|
}
|
|
332
295
|
}
|
|
@@ -346,7 +309,7 @@ export async function captureAndIndex(
|
|
|
346
309
|
} catch {}
|
|
347
310
|
}
|
|
348
311
|
throw new Error(
|
|
349
|
-
`Capture succeeded but indexing failed — file rolled back. ${(err as Error).message}
|
|
312
|
+
`Capture succeeded but indexing failed — file rolled back. ${(err as Error).message}`
|
|
350
313
|
);
|
|
351
314
|
}
|
|
352
315
|
}
|
package/src/categories.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
const KIND_CATEGORY: Record<string, string> = {
|
|
2
|
-
insight:
|
|
3
|
-
decision:
|
|
4
|
-
pattern:
|
|
5
|
-
prompt:
|
|
6
|
-
note:
|
|
7
|
-
document:
|
|
8
|
-
reference:
|
|
9
|
-
contact:
|
|
10
|
-
project:
|
|
11
|
-
tool:
|
|
12
|
-
source:
|
|
13
|
-
bucket:
|
|
14
|
-
event:
|
|
15
|
-
conversation:
|
|
16
|
-
message:
|
|
17
|
-
session:
|
|
18
|
-
task:
|
|
19
|
-
log:
|
|
20
|
-
feedback:
|
|
21
|
-
inbox:
|
|
2
|
+
insight: 'knowledge',
|
|
3
|
+
decision: 'knowledge',
|
|
4
|
+
pattern: 'knowledge',
|
|
5
|
+
prompt: 'knowledge',
|
|
6
|
+
note: 'knowledge',
|
|
7
|
+
document: 'knowledge',
|
|
8
|
+
reference: 'knowledge',
|
|
9
|
+
contact: 'entity',
|
|
10
|
+
project: 'entity',
|
|
11
|
+
tool: 'entity',
|
|
12
|
+
source: 'entity',
|
|
13
|
+
bucket: 'entity',
|
|
14
|
+
event: 'event',
|
|
15
|
+
conversation: 'event',
|
|
16
|
+
message: 'event',
|
|
17
|
+
session: 'event',
|
|
18
|
+
task: 'event',
|
|
19
|
+
log: 'event',
|
|
20
|
+
feedback: 'event',
|
|
21
|
+
inbox: 'event',
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const CATEGORY_DIR_NAMES: Record<string, string> = {
|
|
25
|
-
knowledge:
|
|
26
|
-
entity:
|
|
27
|
-
event:
|
|
25
|
+
knowledge: 'knowledge',
|
|
26
|
+
entity: 'entities',
|
|
27
|
+
event: 'events',
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
export const CATEGORY_DIRS = new Set(Object.values(CATEGORY_DIR_NAMES));
|
|
@@ -35,20 +35,20 @@ export const KIND_STALENESS_DAYS: Record<string, number> = {
|
|
|
35
35
|
reference: 90,
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
const DURABLE_KINDS = new Set([
|
|
39
|
-
const EPHEMERAL_KINDS = new Set([
|
|
38
|
+
const DURABLE_KINDS = new Set(['decision', 'architecture', 'pattern']);
|
|
39
|
+
const EPHEMERAL_KINDS = new Set(['session', 'observation']);
|
|
40
40
|
|
|
41
41
|
export function categoryFor(kind: string): string {
|
|
42
|
-
return KIND_CATEGORY[kind] ||
|
|
42
|
+
return KIND_CATEGORY[kind] || 'knowledge';
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
export function defaultTierFor(kind: string): string {
|
|
46
|
-
if (DURABLE_KINDS.has(kind)) return
|
|
47
|
-
if (EPHEMERAL_KINDS.has(kind)) return
|
|
48
|
-
return
|
|
46
|
+
if (DURABLE_KINDS.has(kind)) return 'durable';
|
|
47
|
+
if (EPHEMERAL_KINDS.has(kind)) return 'ephemeral';
|
|
48
|
+
return 'working';
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export function categoryDirFor(kind: string): string {
|
|
52
52
|
const cat = categoryFor(kind);
|
|
53
|
-
return CATEGORY_DIR_NAMES[cat] ||
|
|
53
|
+
return CATEGORY_DIR_NAMES[cat] || 'knowledge';
|
|
54
54
|
}
|