somtum 0.1.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/LICENSE +663 -0
- package/README.md +459 -0
- package/dist/cli/config_cmd.d.ts +10 -0
- package/dist/cli/config_cmd.d.ts.map +1 -0
- package/dist/cli/config_cmd.js +96 -0
- package/dist/cli/config_cmd.js.map +1 -0
- package/dist/cli/doctor.d.ts +17 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +169 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/edit.d.ts +4 -0
- package/dist/cli/edit.d.ts.map +1 -0
- package/dist/cli/edit.js +63 -0
- package/dist/cli/edit.js.map +1 -0
- package/dist/cli/export.d.ts +19 -0
- package/dist/cli/export.d.ts.map +1 -0
- package/dist/cli/export.js +84 -0
- package/dist/cli/export.js.map +1 -0
- package/dist/cli/forget.d.ts +11 -0
- package/dist/cli/forget.d.ts.map +1 -0
- package/dist/cli/forget.js +32 -0
- package/dist/cli/forget.js.map +1 -0
- package/dist/cli/hook.d.ts +2 -0
- package/dist/cli/hook.d.ts.map +1 -0
- package/dist/cli/hook.js +66 -0
- package/dist/cli/hook.js.map +1 -0
- package/dist/cli/import.d.ts +18 -0
- package/dist/cli/import.d.ts.map +1 -0
- package/dist/cli/import.js +90 -0
- package/dist/cli/import.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +223 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +24 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +144 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/purge.d.ts +16 -0
- package/dist/cli/purge.d.ts.map +1 -0
- package/dist/cli/purge.js +69 -0
- package/dist/cli/purge.js.map +1 -0
- package/dist/cli/rebuild.d.ts +15 -0
- package/dist/cli/rebuild.d.ts.map +1 -0
- package/dist/cli/rebuild.js +41 -0
- package/dist/cli/rebuild.js.map +1 -0
- package/dist/cli/reindex.d.ts +6 -0
- package/dist/cli/reindex.d.ts.map +1 -0
- package/dist/cli/reindex.js +47 -0
- package/dist/cli/reindex.js.map +1 -0
- package/dist/cli/search.d.ts +16 -0
- package/dist/cli/search.d.ts.map +1 -0
- package/dist/cli/search.js +62 -0
- package/dist/cli/search.js.map +1 -0
- package/dist/cli/show.d.ts +12 -0
- package/dist/cli/show.d.ts.map +1 -0
- package/dist/cli/show.js +49 -0
- package/dist/cli/show.js.map +1 -0
- package/dist/cli/stats.d.ts +27 -0
- package/dist/cli/stats.d.ts.map +1 -0
- package/dist/cli/stats.js +80 -0
- package/dist/cli/stats.js.map +1 -0
- package/dist/cli/sync.d.ts +18 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +138 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/config.d.ts +12 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +52 -0
- package/dist/config.js.map +1 -0
- package/dist/core/cache.d.ts +29 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +137 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/db.d.ts +12 -0
- package/dist/core/db.d.ts.map +1 -0
- package/dist/core/db.js +80 -0
- package/dist/core/db.js.map +1 -0
- package/dist/core/embeddings.d.ts +15 -0
- package/dist/core/embeddings.d.ts.map +1 -0
- package/dist/core/embeddings.js +74 -0
- package/dist/core/embeddings.js.map +1 -0
- package/dist/core/embeddings_bootstrap.d.ts +3 -0
- package/dist/core/embeddings_bootstrap.d.ts.map +1 -0
- package/dist/core/embeddings_bootstrap.js +16 -0
- package/dist/core/embeddings_bootstrap.js.map +1 -0
- package/dist/core/embeddings_xenova.d.ts +3 -0
- package/dist/core/embeddings_xenova.d.ts.map +1 -0
- package/dist/core/embeddings_xenova.js +28 -0
- package/dist/core/embeddings_xenova.js.map +1 -0
- package/dist/core/extractor.d.ts +27 -0
- package/dist/core/extractor.d.ts.map +1 -0
- package/dist/core/extractor.js +133 -0
- package/dist/core/extractor.js.map +1 -0
- package/dist/core/file_summary.d.ts +33 -0
- package/dist/core/file_summary.d.ts.map +1 -0
- package/dist/core/file_summary.js +127 -0
- package/dist/core/file_summary.js.map +1 -0
- package/dist/core/fingerprint.d.ts +13 -0
- package/dist/core/fingerprint.d.ts.map +1 -0
- package/dist/core/fingerprint.js +36 -0
- package/dist/core/fingerprint.js.map +1 -0
- package/dist/core/index_gen.d.ts +16 -0
- package/dist/core/index_gen.d.ts.map +1 -0
- package/dist/core/index_gen.js +173 -0
- package/dist/core/index_gen.js.map +1 -0
- package/dist/core/memory_files.d.ts +4 -0
- package/dist/core/memory_files.d.ts.map +1 -0
- package/dist/core/memory_files.js +36 -0
- package/dist/core/memory_files.js.map +1 -0
- package/dist/core/privacy.d.ts +9 -0
- package/dist/core/privacy.d.ts.map +1 -0
- package/dist/core/privacy.js +32 -0
- package/dist/core/privacy.js.map +1 -0
- package/dist/core/project_id.d.ts +3 -0
- package/dist/core/project_id.d.ts.map +1 -0
- package/dist/core/project_id.js +31 -0
- package/dist/core/project_id.js.map +1 -0
- package/dist/core/reindex.d.ts +10 -0
- package/dist/core/reindex.d.ts.map +1 -0
- package/dist/core/reindex.js +40 -0
- package/dist/core/reindex.js.map +1 -0
- package/dist/core/retrieval_stats.d.ts +22 -0
- package/dist/core/retrieval_stats.d.ts.map +1 -0
- package/dist/core/retrieval_stats.js +56 -0
- package/dist/core/retrieval_stats.js.map +1 -0
- package/dist/core/retriever/bm25.d.ts +15 -0
- package/dist/core/retriever/bm25.d.ts.map +1 -0
- package/dist/core/retriever/bm25.js +51 -0
- package/dist/core/retriever/bm25.js.map +1 -0
- package/dist/core/retriever/embeddings.d.ts +9 -0
- package/dist/core/retriever/embeddings.d.ts.map +1 -0
- package/dist/core/retriever/embeddings.js +34 -0
- package/dist/core/retriever/embeddings.js.map +1 -0
- package/dist/core/retriever/factory.d.ts +6 -0
- package/dist/core/retriever/factory.d.ts.map +1 -0
- package/dist/core/retriever/factory.js +53 -0
- package/dist/core/retriever/factory.js.map +1 -0
- package/dist/core/retriever/hybrid.d.ts +14 -0
- package/dist/core/retriever/hybrid.d.ts.map +1 -0
- package/dist/core/retriever/hybrid.js +52 -0
- package/dist/core/retriever/hybrid.js.map +1 -0
- package/dist/core/retriever/llm_index.d.ts +18 -0
- package/dist/core/retriever/llm_index.d.ts.map +1 -0
- package/dist/core/retriever/llm_index.js +90 -0
- package/dist/core/retriever/llm_index.js.map +1 -0
- package/dist/core/retriever/types.d.ts +16 -0
- package/dist/core/retriever/types.d.ts.map +1 -0
- package/dist/core/retriever/types.js +2 -0
- package/dist/core/retriever/types.js.map +1 -0
- package/dist/core/schema.d.ts +470 -0
- package/dist/core/schema.d.ts.map +1 -0
- package/dist/core/schema.js +153 -0
- package/dist/core/schema.js.map +1 -0
- package/dist/core/store.d.ts +35 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +172 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/tokens.d.ts +3 -0
- package/dist/core/tokens.d.ts.map +1 -0
- package/dist/core/tokens.js +12 -0
- package/dist/core/tokens.js.map +1 -0
- package/dist/core/transcript.d.ts +16 -0
- package/dist/core/transcript.d.ts.map +1 -0
- package/dist/core/transcript.js +128 -0
- package/dist/core/transcript.js.map +1 -0
- package/dist/db/migrations/001_init.sql +90 -0
- package/dist/db/migrations/002_cache_files.sql +6 -0
- package/dist/db/migrations/003_retrieval_stats.sql +17 -0
- package/dist/hooks/post_session.d.ts +65 -0
- package/dist/hooks/post_session.d.ts.map +1 -0
- package/dist/hooks/post_session.js +249 -0
- package/dist/hooks/post_session.js.map +1 -0
- package/dist/hooks/pre_prompt.d.ts +55 -0
- package/dist/hooks/pre_prompt.d.ts.map +1 -0
- package/dist/hooks/pre_prompt.js +98 -0
- package/dist/hooks/pre_prompt.js.map +1 -0
- package/dist/hooks/pre_read.d.ts +56 -0
- package/dist/hooks/pre_read.d.ts.map +1 -0
- package/dist/hooks/pre_read.js +77 -0
- package/dist/hooks/pre_read.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +20 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +128 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +72 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +153 -0
- package/dist/mcp/tools.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync, statSync, existsSync } from 'node:fs';
|
|
3
|
+
import { isAbsolute, resolve } from 'node:path';
|
|
4
|
+
import { countTokens } from './tokens.js';
|
|
5
|
+
import { FileFingerprintSchema } from './schema.js';
|
|
6
|
+
export class FileFingerprintStore {
|
|
7
|
+
db;
|
|
8
|
+
constructor(db) {
|
|
9
|
+
this.db = db;
|
|
10
|
+
}
|
|
11
|
+
get(projectId, path) {
|
|
12
|
+
const row = this.db
|
|
13
|
+
.prepare(`SELECT * FROM file_fingerprints WHERE project_id = ? AND path = ?`)
|
|
14
|
+
.get(projectId, path);
|
|
15
|
+
if (!row)
|
|
16
|
+
return null;
|
|
17
|
+
return FileFingerprintSchema.parse({
|
|
18
|
+
project_id: row['project_id'],
|
|
19
|
+
path: row['path'],
|
|
20
|
+
content_hash: row['content_hash'],
|
|
21
|
+
mtime: row['mtime'],
|
|
22
|
+
tokens: row['tokens'],
|
|
23
|
+
summary: row['summary'] ?? null,
|
|
24
|
+
summary_hash: row['summary_hash'] ?? null,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
upsert(input) {
|
|
28
|
+
this.db
|
|
29
|
+
.prepare(`INSERT INTO file_fingerprints
|
|
30
|
+
(project_id, path, content_hash, mtime, tokens, summary, summary_hash)
|
|
31
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
32
|
+
ON CONFLICT(project_id, path) DO UPDATE SET
|
|
33
|
+
content_hash = excluded.content_hash,
|
|
34
|
+
mtime = excluded.mtime,
|
|
35
|
+
tokens = excluded.tokens,
|
|
36
|
+
summary = COALESCE(excluded.summary, file_fingerprints.summary),
|
|
37
|
+
summary_hash = COALESCE(excluded.summary_hash, file_fingerprints.summary_hash)`)
|
|
38
|
+
.run(input.project_id, input.path, input.content_hash, input.mtime, input.tokens, input.summary, input.summary_hash);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function statFile(path, opts) {
|
|
42
|
+
const abs = isAbsolute(path) ? path : resolve(opts.cwd, path);
|
|
43
|
+
if (!existsSync(abs))
|
|
44
|
+
return null;
|
|
45
|
+
let buf;
|
|
46
|
+
let mtime;
|
|
47
|
+
try {
|
|
48
|
+
buf = readFileSync(abs);
|
|
49
|
+
mtime = Math.floor(statSync(abs).mtimeMs);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const text = buf.toString('utf8');
|
|
55
|
+
return {
|
|
56
|
+
contentHash: createHash('sha256').update(buf).digest('hex'),
|
|
57
|
+
mtime,
|
|
58
|
+
tokens: countTokens(text),
|
|
59
|
+
bytes: buf.length,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// Minimal glob → RegExp. Supports `*`, `**`, and `?`. Sufficient for the
|
|
63
|
+
// tiny `exclude_globs` patterns we expect (e.g. `**/*.env`, `**/secrets/**`).
|
|
64
|
+
// For richer patterns we'd pull in `picomatch`, but that's overkill here.
|
|
65
|
+
function globToRegex(pattern) {
|
|
66
|
+
let out = '';
|
|
67
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
68
|
+
const c = pattern[i];
|
|
69
|
+
if (c === '*') {
|
|
70
|
+
if (pattern[i + 1] === '*') {
|
|
71
|
+
out += '.*';
|
|
72
|
+
i += 1;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
out += '[^/]*';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (c === '?') {
|
|
79
|
+
out += '[^/]';
|
|
80
|
+
}
|
|
81
|
+
else if (c && /[.+^${}()|[\]\\]/.test(c)) {
|
|
82
|
+
out += `\\${c}`;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
out += c;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return new RegExp(`^${out}$`);
|
|
89
|
+
}
|
|
90
|
+
export function matchesAnyGlob(path, globs) {
|
|
91
|
+
return globs.some((g) => globToRegex(g).test(path));
|
|
92
|
+
}
|
|
93
|
+
const SUMMARY_SYSTEM = `You are Somtum's file summarizer. Produce a dense summary of a source file so a coding agent can decide whether it needs to read the full content.
|
|
94
|
+
|
|
95
|
+
INCLUDE:
|
|
96
|
+
- The file's purpose in 1-2 sentences
|
|
97
|
+
- Top-level exports/symbols and what each does
|
|
98
|
+
- Important invariants, side effects, or non-obvious constraints
|
|
99
|
+
- Cross-file dependencies worth knowing
|
|
100
|
+
|
|
101
|
+
OMIT:
|
|
102
|
+
- Line-by-line restatement of code
|
|
103
|
+
- Imports list
|
|
104
|
+
- Boilerplate, comments, or formatting
|
|
105
|
+
|
|
106
|
+
Return plain text. Aim for under 400 tokens. No markdown headers.`;
|
|
107
|
+
const DEFAULT_MAX_BYTES = 200_000; // ~50k tokens worth of source — enough for any sane file.
|
|
108
|
+
export async function summarizeFile(path, contents, opts) {
|
|
109
|
+
// Truncate pathologically large files so we don't blow the LLM context.
|
|
110
|
+
const max = opts.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
111
|
+
const body = contents.length > max
|
|
112
|
+
? `${contents.slice(0, max)}\n\n[... file truncated at ${max} bytes for summarization ...]`
|
|
113
|
+
: contents;
|
|
114
|
+
const { text, inputTokens, outputTokens } = await opts.caller.complete({
|
|
115
|
+
model: opts.model,
|
|
116
|
+
system: SUMMARY_SYSTEM,
|
|
117
|
+
user: `File: ${path}\n\n${body}`,
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
summary: text.trim(),
|
|
121
|
+
tokensSpent: inputTokens + outputTokens,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export function summaryHash(summary) {
|
|
125
|
+
return createHash('sha256').update(summary).digest('hex');
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=file_summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file_summary.js","sourceRoot":"","sources":["../../src/core/file_summary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface FileHash {
|
|
2
|
+
path: string;
|
|
3
|
+
hash: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function hashContent(content: string | Buffer): string;
|
|
6
|
+
export declare function hashFilesTouched(files: FileHash[]): string;
|
|
7
|
+
export declare function fingerprintFiles(paths: string[], opts: {
|
|
8
|
+
cwd: string;
|
|
9
|
+
}): {
|
|
10
|
+
fingerprint: string;
|
|
11
|
+
files: FileHash[];
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=fingerprint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/core/fingerprint.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAU1D;AAMD,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GACpB;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,CAW5C"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
3
|
+
import { resolve, isAbsolute } from 'node:path';
|
|
4
|
+
export function hashContent(content) {
|
|
5
|
+
return createHash('sha256').update(content).digest('hex');
|
|
6
|
+
}
|
|
7
|
+
export function hashFilesTouched(files) {
|
|
8
|
+
const sorted = [...files].sort((a, b) => a.path.localeCompare(b.path));
|
|
9
|
+
const h = createHash('sha256');
|
|
10
|
+
for (const f of sorted) {
|
|
11
|
+
h.update(f.path);
|
|
12
|
+
h.update('\x00');
|
|
13
|
+
h.update(f.hash);
|
|
14
|
+
h.update('\x00');
|
|
15
|
+
}
|
|
16
|
+
return h.digest('hex');
|
|
17
|
+
}
|
|
18
|
+
// Resolves each path relative to cwd (if not already absolute) and reads it
|
|
19
|
+
// from disk. Missing files are included with hash='<missing>' so that a
|
|
20
|
+
// later-created file shows up as a fingerprint change and invalidates
|
|
21
|
+
// the entry rather than matching silently.
|
|
22
|
+
export function fingerprintFiles(paths, opts) {
|
|
23
|
+
const files = paths.map((p) => {
|
|
24
|
+
const abs = isAbsolute(p) ? p : resolve(opts.cwd, p);
|
|
25
|
+
if (!existsSync(abs))
|
|
26
|
+
return { path: p, hash: '<missing>' };
|
|
27
|
+
try {
|
|
28
|
+
return { path: p, hash: hashContent(readFileSync(abs)) };
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return { path: p, hash: '<unreadable>' };
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
return { fingerprint: hashFilesTouched(files), files };
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/core/fingerprint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAWhD,MAAM,UAAU,WAAW,CAAC,OAAwB;IAClD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,KAAiB;IAChD,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACvE,MAAM,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACjB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzB,CAAC;AAED,4EAA4E;AAC5E,wEAAwE;AACxE,sEAAsE;AACtE,2CAA2C;AAC3C,MAAM,UAAU,gBAAgB,CAC9B,KAAe,EACf,IAAqB;IAErB,MAAM,KAAK,GAAe,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACxC,MAAM,GAAG,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;QAC5D,IAAI,CAAC;YACH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,WAAW,EAAE,gBAAgB,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MemoryStore } from './store.js';
|
|
2
|
+
import type { Observation } from './schema.js';
|
|
3
|
+
export interface IndexOptions {
|
|
4
|
+
projectName: string;
|
|
5
|
+
totalTokensSaved: number;
|
|
6
|
+
now?: number;
|
|
7
|
+
recentDays?: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function renderIndex(obs: Observation[], opts: IndexOptions): string;
|
|
10
|
+
export interface GenerateOptions extends IndexOptions {
|
|
11
|
+
store: MemoryStore;
|
|
12
|
+
projectId: string;
|
|
13
|
+
outputPath: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function generateIndex(options: GenerateOptions): string;
|
|
16
|
+
//# sourceMappingURL=index_gen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index_gen.d.ts","sourceRoot":"","sources":["../../src/core/index_gen.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,aAAa,CAAC;AAwChE,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAqID,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAE1E;AAED,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAiB9D"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
const HEADER_COMMENT = '<!-- This file is regenerated by somtum. Edits will be overwritten. To modify, use: somtum edit <id> -->';
|
|
4
|
+
const KIND_TITLES = {
|
|
5
|
+
decision: 'Decisions',
|
|
6
|
+
learning: 'Learnings',
|
|
7
|
+
bugfix: 'Bugfixes',
|
|
8
|
+
file_summary: 'File summaries',
|
|
9
|
+
command: 'Commands',
|
|
10
|
+
other: 'Other',
|
|
11
|
+
};
|
|
12
|
+
const ISO_DAY = (ms) => new Date(ms).toISOString().slice(0, 10);
|
|
13
|
+
// Threshold above which we switch to the incremental rendering path that
|
|
14
|
+
// avoids loading all observations into memory at once.
|
|
15
|
+
const INCREMENTAL_THRESHOLD = 1000;
|
|
16
|
+
// Max entries shown per kind section in incremental mode.
|
|
17
|
+
const INCREMENTAL_KIND_LIMIT = 20;
|
|
18
|
+
function groupByKind(obs) {
|
|
19
|
+
const out = {
|
|
20
|
+
decision: [],
|
|
21
|
+
learning: [],
|
|
22
|
+
bugfix: [],
|
|
23
|
+
file_summary: [],
|
|
24
|
+
command: [],
|
|
25
|
+
other: [],
|
|
26
|
+
};
|
|
27
|
+
for (const o of obs)
|
|
28
|
+
out[o.kind].push(o);
|
|
29
|
+
return out;
|
|
30
|
+
}
|
|
31
|
+
function formatLine(o) {
|
|
32
|
+
const files = o.files.length > 0 ? ` — ${o.files.map((f) => `\`${f}\``).join(', ')}` : '';
|
|
33
|
+
return `- [${ISO_DAY(o.created_at)}] \`${o.id}\` ${o.title}${files}`;
|
|
34
|
+
}
|
|
35
|
+
// Full render path: loads all observations into memory. Used when total < INCREMENTAL_THRESHOLD.
|
|
36
|
+
function renderFull(obs, opts) {
|
|
37
|
+
const now = opts.now ?? Date.now();
|
|
38
|
+
const recentDays = opts.recentDays ?? 7;
|
|
39
|
+
const recentCutoff = now - recentDays * 24 * 60 * 60 * 1000;
|
|
40
|
+
const byKind = groupByKind(obs);
|
|
41
|
+
const byFile = new Map();
|
|
42
|
+
for (const o of obs) {
|
|
43
|
+
for (const f of o.files) {
|
|
44
|
+
const list = byFile.get(f) ?? [];
|
|
45
|
+
list.push(o.id);
|
|
46
|
+
byFile.set(f, list);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const recent = obs
|
|
50
|
+
.filter((o) => o.created_at >= recentCutoff)
|
|
51
|
+
.sort((a, b) => b.created_at - a.created_at);
|
|
52
|
+
const sections = [];
|
|
53
|
+
sections.push(HEADER_COMMENT);
|
|
54
|
+
sections.push('');
|
|
55
|
+
sections.push(`# ${opts.projectName} Memory Index`);
|
|
56
|
+
sections.push('');
|
|
57
|
+
sections.push(`Last updated: ${new Date(now).toISOString()}. ${obs.length} memories. ${opts.totalTokensSaved} tokens saved cumulative (estimated).`);
|
|
58
|
+
sections.push('');
|
|
59
|
+
sections.push('## By kind');
|
|
60
|
+
sections.push('');
|
|
61
|
+
for (const kind of Object.keys(KIND_TITLES)) {
|
|
62
|
+
const list = byKind[kind];
|
|
63
|
+
if (list.length === 0)
|
|
64
|
+
continue;
|
|
65
|
+
sections.push(`### ${KIND_TITLES[kind]} (${list.length})`);
|
|
66
|
+
sections.push('');
|
|
67
|
+
const sorted = [...list].sort((a, b) => b.created_at - a.created_at);
|
|
68
|
+
for (const o of sorted)
|
|
69
|
+
sections.push(formatLine(o));
|
|
70
|
+
sections.push('');
|
|
71
|
+
}
|
|
72
|
+
if (byFile.size > 0) {
|
|
73
|
+
sections.push('## By file (most-referenced)');
|
|
74
|
+
sections.push('');
|
|
75
|
+
const entries = [...byFile.entries()].sort((a, b) => b[1].length - a[1].length).slice(0, 20);
|
|
76
|
+
for (const [file, ids] of entries) {
|
|
77
|
+
sections.push(`- \`${file}\` — ${ids.length} memories: ${ids.map((i) => `\`${i}\``).join(', ')}`);
|
|
78
|
+
}
|
|
79
|
+
sections.push('');
|
|
80
|
+
}
|
|
81
|
+
sections.push(`## Recent (last ${recentDays} days)`);
|
|
82
|
+
sections.push('');
|
|
83
|
+
if (recent.length === 0) {
|
|
84
|
+
sections.push('- _none_');
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
for (const o of recent)
|
|
88
|
+
sections.push(formatLine(o));
|
|
89
|
+
}
|
|
90
|
+
sections.push('');
|
|
91
|
+
return sections.join('\n');
|
|
92
|
+
}
|
|
93
|
+
// Incremental render path: avoids loading all observations. Uses targeted
|
|
94
|
+
// SQL queries (counts, recent, per-kind limits) so memory and time stay
|
|
95
|
+
// bounded even at 10k+ observations.
|
|
96
|
+
function renderIncremental(store, projectId, opts) {
|
|
97
|
+
const now = opts.now ?? Date.now();
|
|
98
|
+
const recentDays = opts.recentDays ?? 7;
|
|
99
|
+
const recentCutoff = now - recentDays * 24 * 60 * 60 * 1000;
|
|
100
|
+
const totalCount = store.countByProject(projectId);
|
|
101
|
+
const byKindCounts = store.countByKind(projectId);
|
|
102
|
+
const recentObs = store.listRecent(projectId, recentCutoff, 100);
|
|
103
|
+
const topFiles = store.topFileReferences(projectId, 20);
|
|
104
|
+
const sections = [];
|
|
105
|
+
sections.push(HEADER_COMMENT);
|
|
106
|
+
sections.push('');
|
|
107
|
+
sections.push(`# ${opts.projectName} Memory Index`);
|
|
108
|
+
sections.push('');
|
|
109
|
+
sections.push(`Last updated: ${new Date(now).toISOString()}. ${totalCount} memories. ${opts.totalTokensSaved} tokens saved cumulative (estimated).`);
|
|
110
|
+
sections.push('');
|
|
111
|
+
sections.push('## By kind');
|
|
112
|
+
sections.push('');
|
|
113
|
+
for (const kind of Object.keys(KIND_TITLES)) {
|
|
114
|
+
const count = byKindCounts[kind] ?? 0;
|
|
115
|
+
if (count === 0)
|
|
116
|
+
continue;
|
|
117
|
+
const recent = store.listByKind(projectId, kind, INCREMENTAL_KIND_LIMIT);
|
|
118
|
+
sections.push(`### ${KIND_TITLES[kind]} (${count})`);
|
|
119
|
+
sections.push('');
|
|
120
|
+
for (const o of recent)
|
|
121
|
+
sections.push(formatLine(o));
|
|
122
|
+
if (count > INCREMENTAL_KIND_LIMIT) {
|
|
123
|
+
sections.push(`- _… and ${count - INCREMENTAL_KIND_LIMIT} more — use \`somtum search\` to explore_`);
|
|
124
|
+
}
|
|
125
|
+
sections.push('');
|
|
126
|
+
}
|
|
127
|
+
if (topFiles.length > 0) {
|
|
128
|
+
sections.push('## By file (most-referenced)');
|
|
129
|
+
sections.push('');
|
|
130
|
+
for (const { file, count, ids } of topFiles) {
|
|
131
|
+
const shown = ids
|
|
132
|
+
.slice(0, 10)
|
|
133
|
+
.map((i) => `\`${i}\``)
|
|
134
|
+
.join(', ');
|
|
135
|
+
const extra = ids.length > 10 ? ` … +${ids.length - 10} more` : '';
|
|
136
|
+
sections.push(`- \`${file}\` — ${count} memories: ${shown}${extra}`);
|
|
137
|
+
}
|
|
138
|
+
sections.push('');
|
|
139
|
+
}
|
|
140
|
+
sections.push(`## Recent (last ${recentDays} days)`);
|
|
141
|
+
sections.push('');
|
|
142
|
+
if (recentObs.length === 0) {
|
|
143
|
+
sections.push('- _none_');
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
for (const o of recentObs)
|
|
147
|
+
sections.push(formatLine(o));
|
|
148
|
+
}
|
|
149
|
+
sections.push('');
|
|
150
|
+
return sections.join('\n');
|
|
151
|
+
}
|
|
152
|
+
export function renderIndex(obs, opts) {
|
|
153
|
+
return renderFull(obs, opts);
|
|
154
|
+
}
|
|
155
|
+
export function generateIndex(options) {
|
|
156
|
+
const totalCount = options.store.countByProject(options.projectId);
|
|
157
|
+
let md;
|
|
158
|
+
if (totalCount >= INCREMENTAL_THRESHOLD) {
|
|
159
|
+
// Incremental path: SQL-driven, bounded memory usage.
|
|
160
|
+
md = renderIncremental(options.store, options.projectId, options);
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
// Full path: load all observations once, render in-memory.
|
|
164
|
+
const obs = options.store.listByProject(options.projectId);
|
|
165
|
+
md = renderFull(obs, options);
|
|
166
|
+
}
|
|
167
|
+
const dir = dirname(options.outputPath);
|
|
168
|
+
if (!existsSync(dir))
|
|
169
|
+
mkdirSync(dir, { recursive: true });
|
|
170
|
+
writeFileSync(options.outputPath, md, 'utf8');
|
|
171
|
+
return md;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=index_gen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index_gen.js","sourceRoot":"","sources":["../../src/core/index_gen.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory_files.d.ts","sourceRoot":"","sources":["../../src/core/memory_files.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAmB/C,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CASjF;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtD"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Writes individual per-observation markdown files as the human-readable mirror
|
|
2
|
+
// described in SPEC.md §5.2: memories/<YYYY-MM>/<ulid>.md
|
|
3
|
+
// SQLite is the source of truth; these files are derived and regenerated on import.
|
|
4
|
+
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
function isoMonth(ms) {
|
|
7
|
+
return new Date(ms).toISOString().slice(0, 7); // "2026-04"
|
|
8
|
+
}
|
|
9
|
+
function frontmatter(obs) {
|
|
10
|
+
const lines = ['---'];
|
|
11
|
+
lines.push(`id: ${obs.id}`);
|
|
12
|
+
lines.push(`kind: ${obs.kind}`);
|
|
13
|
+
lines.push(`created: ${new Date(obs.created_at).toISOString()}`);
|
|
14
|
+
if (obs.files.length > 0)
|
|
15
|
+
lines.push(`files: [${obs.files.map((f) => `"${f}"`).join(', ')}]`);
|
|
16
|
+
if (obs.tags.length > 0)
|
|
17
|
+
lines.push(`tags: [${obs.tags.map((t) => `"${t}"`).join(', ')}]`);
|
|
18
|
+
lines.push(`tokens_saved: ${obs.tokens_saved}`);
|
|
19
|
+
lines.push(`tokens_spent: ${obs.tokens_spent}`);
|
|
20
|
+
lines.push('---');
|
|
21
|
+
return lines.join('\n');
|
|
22
|
+
}
|
|
23
|
+
export function writeMemoryMarkdown(obs, memoriesDir) {
|
|
24
|
+
const month = isoMonth(obs.created_at);
|
|
25
|
+
const monthDir = join(memoriesDir, month);
|
|
26
|
+
if (!existsSync(monthDir))
|
|
27
|
+
mkdirSync(monthDir, { recursive: true });
|
|
28
|
+
const filePath = join(monthDir, `${obs.id}.md`);
|
|
29
|
+
const content = `${frontmatter(obs)}\n\n# ${obs.title}\n\n${obs.body}\n`;
|
|
30
|
+
writeFileSync(filePath, content, 'utf8');
|
|
31
|
+
return filePath;
|
|
32
|
+
}
|
|
33
|
+
export function memoriesDir(projectDir) {
|
|
34
|
+
return join(projectDir, 'memories');
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=memory_files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory_files.js","sourceRoot":"","sources":["../../src/core/memory_files.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,0DAA0D;AAC1D,oFAAoF;AACpF,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,SAAS,QAAQ,CAAC,EAAU;IAC1B,OAAO,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY;AAC7D,CAAC;AAED,SAAS,WAAW,CAAC,GAAgB;IACnC,MAAM,KAAK,GAAa,CAAC,KAAK,CAAC,CAAC;IAChC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5B,KAAK,CAAC,IAAI,CAAC,SAAS,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAChC,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IACjE,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC9F,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC3F,KAAK,CAAC,IAAI,CAAC,iBAAiB,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;IAChD,KAAK,CAAC,IAAI,CAAC,iBAAiB,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC;IAChD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAgB,EAAE,WAAmB;IACvE,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC1C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEpE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,SAAS,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC;IACzE,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACzC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,UAAkB;IAC5C,OAAO,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const REDACTION_PLACEHOLDER = "[REDACTED]";
|
|
2
|
+
export interface RedactOptions {
|
|
3
|
+
patterns: string[];
|
|
4
|
+
flags?: string;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function redact(text: string, options: RedactOptions): string;
|
|
8
|
+
export declare function redactAll(text: string, patterns: string[]): string;
|
|
9
|
+
//# sourceMappingURL=privacy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"privacy.d.ts","sourceRoot":"","sources":["../../src/core/privacy.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB,eAAe,CAAC;AAElD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAeD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CASnE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAElE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Redaction runs on every capture, even when telemetry is disabled.
|
|
2
|
+
// Keep this module side-effect-free so the capture hook can call it
|
|
3
|
+
// unconditionally before writing to the DB.
|
|
4
|
+
export const REDACTION_PLACEHOLDER = '[REDACTED]';
|
|
5
|
+
function compile(patterns, flags) {
|
|
6
|
+
const compiled = [];
|
|
7
|
+
for (const p of patterns) {
|
|
8
|
+
try {
|
|
9
|
+
compiled.push(new RegExp(p, flags));
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
// One malformed pattern must not disable the rest.
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return compiled;
|
|
17
|
+
}
|
|
18
|
+
export function redact(text, options) {
|
|
19
|
+
if (!text)
|
|
20
|
+
return text;
|
|
21
|
+
const placeholder = options.placeholder ?? REDACTION_PLACEHOLDER;
|
|
22
|
+
const regexes = compile(options.patterns, options.flags ?? 'gi');
|
|
23
|
+
let out = text;
|
|
24
|
+
for (const re of regexes) {
|
|
25
|
+
out = out.replace(re, placeholder);
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
export function redactAll(text, patterns) {
|
|
30
|
+
return redact(text, { patterns });
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=privacy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"privacy.js","sourceRoot":"","sources":["../../src/core/privacy.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,oEAAoE;AACpE,4CAA4C;AAE5C,MAAM,CAAC,MAAM,qBAAqB,GAAG,YAAY,CAAC;AAQlD,SAAS,OAAO,CAAC,QAAkB,EAAE,KAAa;IAChD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,mDAAmD;YACnD,SAAS;QACX,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAY,EAAE,OAAsB;IACzD,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,qBAAqB,CAAC;IACjE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;IACjE,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,QAAkB;IACxD,OAAO,MAAM,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project_id.d.ts","sourceRoot":"","sources":["../../src/core/project_id.ts"],"names":[],"mappings":"AAOA,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAIpD;AAgBD,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGtD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { execFileSync } from 'node:child_process';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
// project_id = sha256(git remote origin URL) for git repos, or sha256(cwd)
|
|
6
|
+
// otherwise. Stable across machines for the same repo.
|
|
7
|
+
export function resolveProjectId(cwd) {
|
|
8
|
+
const remote = tryGitRemote(cwd);
|
|
9
|
+
const source = remote ?? cwd;
|
|
10
|
+
return createHash('sha256').update(source).digest('hex').slice(0, 16);
|
|
11
|
+
}
|
|
12
|
+
function tryGitRemote(cwd) {
|
|
13
|
+
if (!existsSync(join(cwd, '.git')))
|
|
14
|
+
return null;
|
|
15
|
+
try {
|
|
16
|
+
const out = execFileSync('git', ['-C', cwd, 'config', '--get', 'remote.origin.url'], {
|
|
17
|
+
encoding: 'utf8',
|
|
18
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
19
|
+
});
|
|
20
|
+
const trimmed = out.trim();
|
|
21
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function projectNameFromCwd(cwd) {
|
|
28
|
+
const parts = cwd.split(/[/\\]/).filter((p) => p.length > 0);
|
|
29
|
+
return parts.at(-1) ?? 'project';
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=project_id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project_id.js","sourceRoot":"","sources":["../../src/core/project_id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,2EAA2E;AAC3E,uDAAuD;AACvD,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,MAAM,IAAI,GAAG,CAAC;IAC7B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,mBAAmB,CAAC,EAAE;YACnF,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7D,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DB } from './db.js';
|
|
2
|
+
export interface ReindexResult {
|
|
3
|
+
embedded: number;
|
|
4
|
+
failed: number;
|
|
5
|
+
}
|
|
6
|
+
export declare function embedMissing(db: DB, projectId: string, opts?: {
|
|
7
|
+
batchSize?: number;
|
|
8
|
+
onProgress?: (done: number, total: number) => void;
|
|
9
|
+
}): Promise<ReindexResult>;
|
|
10
|
+
//# sourceMappingURL=reindex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reindex.d.ts","sourceRoot":"","sources":["../../src/core/reindex.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAKlC,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AAWD,wBAAsB,YAAY,CAChC,EAAE,EAAE,EAAE,EACN,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAAO,GACpF,OAAO,CAAC,aAAa,CAAC,CA0BxB"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { MemoryStore } from './store.js';
|
|
2
|
+
import { encodeVector, getEmbedder } from './embeddings.js';
|
|
3
|
+
function textForObservation(obs) {
|
|
4
|
+
// bge models benefit from a compact query-style concatenation; the
|
|
5
|
+
// order matches what the retriever will ultimately see on the read side.
|
|
6
|
+
return `${obs.title}\n\n${obs.body}`;
|
|
7
|
+
}
|
|
8
|
+
// Walks all un-embedded observations for a project, embeds them in batches,
|
|
9
|
+
// and persists each vector back onto the row. Safe to re-run; already-embedded
|
|
10
|
+
// rows are skipped by `listMissingEmbeddings`.
|
|
11
|
+
export async function embedMissing(db, projectId, opts = {}) {
|
|
12
|
+
const store = new MemoryStore(db);
|
|
13
|
+
const batchSize = opts.batchSize ?? 16;
|
|
14
|
+
const pending = store.listMissingEmbeddings(projectId, 10_000);
|
|
15
|
+
if (pending.length === 0)
|
|
16
|
+
return { embedded: 0, failed: 0 };
|
|
17
|
+
const embedder = await getEmbedder();
|
|
18
|
+
let embedded = 0;
|
|
19
|
+
let failed = 0;
|
|
20
|
+
for (let i = 0; i < pending.length; i += batchSize) {
|
|
21
|
+
const batch = pending.slice(i, i + batchSize);
|
|
22
|
+
try {
|
|
23
|
+
const vectors = await embedder.embed(batch.map(textForObservation));
|
|
24
|
+
batch.forEach((obs, j) => {
|
|
25
|
+
const v = vectors[j];
|
|
26
|
+
if (!v)
|
|
27
|
+
return;
|
|
28
|
+
store.setEmbedding(obs.id, encodeVector(v));
|
|
29
|
+
embedded += 1;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
failed += batch.length;
|
|
34
|
+
}
|
|
35
|
+
if (opts.onProgress)
|
|
36
|
+
opts.onProgress(Math.min(i + batchSize, pending.length), pending.length);
|
|
37
|
+
}
|
|
38
|
+
return { embedded, failed };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=reindex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reindex.js","sourceRoot":"","sources":["../../src/core/reindex.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAQ5D,SAAS,kBAAkB,CAAC,GAAgB;IAC1C,mEAAmE;IACnE,yEAAyE;IACzE,OAAO,GAAG,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;AACvC,CAAC;AAED,4EAA4E;AAC5E,+EAA+E;AAC/E,+CAA+C;AAC/C,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,EAAM,EACN,SAAiB,EACjB,OAAmF,EAAE;IAErF,MAAM,KAAK,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC;IACvC,MAAM,OAAO,GAAG,KAAK,CAAC,qBAAqB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC/D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAE5D,MAAM,QAAQ,GAAG,MAAM,WAAW,EAAE,CAAC;IACrC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;QACnD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC;YACpE,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;gBACvB,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gBACrB,IAAI,CAAC,CAAC;oBAAE,OAAO;gBACf,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5C,QAAQ,IAAI,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC;QACzB,CAAC;QACD,IAAI,IAAI,CAAC,UAAU;YAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DB } from './db.js';
|
|
2
|
+
import type { RetrievalStrategy } from './schema.js';
|
|
3
|
+
export interface RetrievalBreakdown {
|
|
4
|
+
strategy: RetrievalStrategy;
|
|
5
|
+
call_count: number;
|
|
6
|
+
last_called_at: number | null;
|
|
7
|
+
}
|
|
8
|
+
export interface CacheHitSummary {
|
|
9
|
+
hit_count: number;
|
|
10
|
+
miss_count: number;
|
|
11
|
+
hit_rate: number | null;
|
|
12
|
+
}
|
|
13
|
+
export declare class RetrievalStatsStore {
|
|
14
|
+
private readonly db;
|
|
15
|
+
constructor(db: DB);
|
|
16
|
+
incrementRetrieval(projectId: string, strategy: RetrievalStrategy): void;
|
|
17
|
+
incrementCacheHit(projectId: string): void;
|
|
18
|
+
incrementCacheMiss(projectId: string): void;
|
|
19
|
+
getRetrievalBreakdown(projectId: string): RetrievalBreakdown[];
|
|
20
|
+
getCacheHitSummary(projectId: string): CacheHitSummary;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=retrieval_stats.d.ts.map
|