@pcircle/memesh 4.8.1 → 4.8.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +7 -1
- package/README.de.md +1 -1
- package/README.md +1 -1
- package/README.zh-TW.md +1 -1
- package/dashboard/dist/index.html +9 -9
- package/dist/core/agent-message-inbox.d.ts +9 -0
- package/dist/core/agent-message-inbox.d.ts.map +1 -0
- package/dist/core/agent-message-inbox.js +26 -0
- package/dist/core/agent-message-inbox.js.map +1 -0
- package/dist/core/briefing.d.ts.map +1 -1
- package/dist/core/briefing.js +5 -1
- package/dist/core/briefing.js.map +1 -1
- package/dist/core/config.d.ts +4 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +12 -3
- package/dist/core/config.js.map +1 -1
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +5 -2
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/dreamer.d.ts +2 -0
- package/dist/core/dreamer.d.ts.map +1 -1
- package/dist/core/dreamer.js +7 -1
- package/dist/core/dreamer.js.map +1 -1
- package/dist/core/lesson-engine.d.ts +2 -1
- package/dist/core/lesson-engine.d.ts.map +1 -1
- package/dist/core/lesson-engine.js +5 -2
- package/dist/core/lesson-engine.js.map +1 -1
- package/dist/core/lesson-slug.d.ts +2 -0
- package/dist/core/lesson-slug.d.ts.map +1 -0
- package/dist/core/lesson-slug.js +12 -0
- package/dist/core/lesson-slug.js.map +1 -0
- package/dist/core/llm-client.js +1 -1
- package/dist/core/llm-client.js.map +1 -1
- package/dist/core/llm-validator.d.ts +4 -1
- package/dist/core/llm-validator.d.ts.map +1 -1
- package/dist/core/llm-validator.js +59 -30
- package/dist/core/llm-validator.js.map +1 -1
- package/dist/core/operations.d.ts +9 -3
- package/dist/core/operations.d.ts.map +1 -1
- package/dist/core/operations.js +18 -14
- package/dist/core/operations.js.map +1 -1
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +2 -3
- package/dist/core/paths.js.map +1 -1
- package/dist/core/schema-export.js +2 -2
- package/dist/core/schema-export.js.map +1 -1
- package/dist/core/transcript-extractor.d.ts.map +1 -1
- package/dist/core/transcript-extractor.js +2 -2
- package/dist/core/transcript-extractor.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +12 -0
- package/dist/db.js.map +1 -1
- package/dist/skills-manifest.json +14 -9
- package/dist/storage/graph-repairs.d.ts +12 -0
- package/dist/storage/graph-repairs.d.ts.map +1 -0
- package/dist/storage/graph-repairs.js +194 -0
- package/dist/storage/graph-repairs.js.map +1 -0
- package/dist/transports/http/server.d.ts.map +1 -1
- package/dist/transports/http/server.js +117 -7
- package/dist/transports/http/server.js.map +1 -1
- package/dist/transports/mcp/handlers.d.ts +1 -1
- package/dist/transports/mcp/handlers.js +1 -1
- package/dist/transports/mcp/handlers.js.map +1 -1
- package/package.json +13 -3
- package/scripts/hooks/_generated/agent-message-inbox.js +33 -0
- package/scripts/hooks/_generated/core-paths.js +2 -3
- package/scripts/hooks/session-start.js +34 -7
- package/scripts/hooks/session-summary.js +40 -1
- package/skills/memesh/SKILL.md +17 -1
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"entries": [
|
|
4
4
|
{
|
|
5
5
|
"path": ".claude-plugin/plugin.json",
|
|
6
|
-
"sha256": "
|
|
6
|
+
"sha256": "3af9a5e8c6a08ef45c179f98040b79b46efb73d1c5696825dc3bb49cdcc0fd8e",
|
|
7
7
|
"bytes": 527
|
|
8
8
|
},
|
|
9
9
|
{
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
"sha256": "f39efb39a90594141cf7b5e79062b42f7376f7e0007307040b4fed77022fd024",
|
|
17
17
|
"bytes": 2083
|
|
18
18
|
},
|
|
19
|
+
{
|
|
20
|
+
"path": "scripts/hooks/_generated/agent-message-inbox.js",
|
|
21
|
+
"sha256": "32eefdac2b8699bf33ed0b111fad5e374cc64dba0f17b95d4475f30243cef290",
|
|
22
|
+
"bytes": 1394
|
|
23
|
+
},
|
|
19
24
|
{
|
|
20
25
|
"path": "scripts/hooks/_generated/capture-flag.js",
|
|
21
26
|
"sha256": "926c85a60b4ff4ac391666dad392f16358e875a14f2dda66edf99b1d636a0a38",
|
|
@@ -28,8 +33,8 @@
|
|
|
28
33
|
},
|
|
29
34
|
{
|
|
30
35
|
"path": "scripts/hooks/_generated/core-paths.js",
|
|
31
|
-
"sha256": "
|
|
32
|
-
"bytes":
|
|
36
|
+
"sha256": "d9aaba0b0a33b701bc05db9a4b73fe42715279796a77db563767c224c35986c3",
|
|
37
|
+
"bytes": 5244
|
|
33
38
|
},
|
|
34
39
|
{
|
|
35
40
|
"path": "scripts/hooks/_generated/fts-index.js",
|
|
@@ -103,13 +108,13 @@
|
|
|
103
108
|
},
|
|
104
109
|
{
|
|
105
110
|
"path": "scripts/hooks/session-start.js",
|
|
106
|
-
"sha256": "
|
|
107
|
-
"bytes":
|
|
111
|
+
"sha256": "9dd8010551deb8a4016d2963f83a1699313f40302bd714b082b5ec82aa71c467",
|
|
112
|
+
"bytes": 60042
|
|
108
113
|
},
|
|
109
114
|
{
|
|
110
115
|
"path": "scripts/hooks/session-summary.js",
|
|
111
|
-
"sha256": "
|
|
112
|
-
"bytes":
|
|
116
|
+
"sha256": "71c9a38f7b1c0b3f84ec8f51d5b5c79e9cca5bb6ae84b72d2b6bccc77f0fd38d",
|
|
117
|
+
"bytes": 49691
|
|
113
118
|
},
|
|
114
119
|
{
|
|
115
120
|
"path": "scripts/hooks/user-prompt-intent.js",
|
|
@@ -123,8 +128,8 @@
|
|
|
123
128
|
},
|
|
124
129
|
{
|
|
125
130
|
"path": "skills/memesh/SKILL.md",
|
|
126
|
-
"sha256": "
|
|
127
|
-
"bytes":
|
|
131
|
+
"sha256": "56f4a8352f75526a57fc3aa3b58bbd7ba1ef63c289a150cc842c182a055b3d2d",
|
|
132
|
+
"bytes": 15089
|
|
128
133
|
}
|
|
129
134
|
]
|
|
130
135
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MemeshDatabase } from './sqlite.js';
|
|
2
|
+
export declare const SESSION_DEDUPE_KEY = "session_observation_dedupe";
|
|
3
|
+
export declare const ZERO_EDIT_RETRACT_KEY = "session_zero_edit_retract";
|
|
4
|
+
export declare const FUSED_LESSON_SPLIT_KEY = "fused_lesson_split";
|
|
5
|
+
export declare function dedupeSessionObservations(db: MemeshDatabase): number;
|
|
6
|
+
export declare function bashWritesFiles(command: string): boolean;
|
|
7
|
+
export declare function retractZeroEditClaims(db: MemeshDatabase): number;
|
|
8
|
+
export declare function splitFusedLessons(db: MemeshDatabase, deps: {
|
|
9
|
+
deriveTitle: (type: string, observations: string[]) => string | null;
|
|
10
|
+
markReindexOwed: (conn: MemeshDatabase) => void;
|
|
11
|
+
}): number;
|
|
12
|
+
//# sourceMappingURL=graph-repairs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-repairs.d.ts","sourceRoot":"","sources":["../../src/storage/graph-repairs.ts"],"names":[],"mappings":"AAwDA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKlD,eAAO,MAAM,kBAAkB,+BAA+B,CAAC;AAC/D,eAAO,MAAM,qBAAqB,8BAA8B,CAAC;AACjE,eAAO,MAAM,sBAAsB,uBAAuB,CAAC;AAyB3D,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,cAAc,GAAG,MAAM,CA2BpE;AAoBD,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAUxD;AAgBD,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,cAAc,GAAG,MAAM,CAgChE;AA4CD,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,cAAc,EAClB,IAAI,EAAE;IACJ,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,MAAM,GAAG,IAAI,CAAC;IACrE,eAAe,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;CACjD,GACA,MAAM,CA0HR"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { rebuildFtsIndex, runOnceMigration } from './schema.js';
|
|
2
|
+
import { lessonSlug } from '../core/lesson-slug.js';
|
|
3
|
+
import { computeSignalScore } from '../core/signal-scorer.js';
|
|
4
|
+
export const SESSION_DEDUPE_KEY = 'session_observation_dedupe';
|
|
5
|
+
export const ZERO_EDIT_RETRACT_KEY = 'session_zero_edit_retract';
|
|
6
|
+
export const FUSED_LESSON_SPLIT_KEY = 'fused_lesson_split';
|
|
7
|
+
const ZERO_EDITS = ', 0 files edited';
|
|
8
|
+
const ZERO_EDITS_RETRACTED = ', files edited through Bash (count not recorded before 4.8.2)';
|
|
9
|
+
function note(line) {
|
|
10
|
+
process.stderr.write(`MeMesh: ${line}\n`);
|
|
11
|
+
}
|
|
12
|
+
export function dedupeSessionObservations(db) {
|
|
13
|
+
let removed = -1;
|
|
14
|
+
runOnceMigration(db, {
|
|
15
|
+
key: SESSION_DEDUPE_KEY,
|
|
16
|
+
version: 1,
|
|
17
|
+
describe: 'session observation dedupe',
|
|
18
|
+
migrate: (conn) => {
|
|
19
|
+
const affected = conn
|
|
20
|
+
.prepare(`SELECT DISTINCT e.id FROM entities e JOIN observations o ON o.entity_id = e.id
|
|
21
|
+
WHERE e.name LIKE 'session-%'
|
|
22
|
+
GROUP BY e.id, o.content HAVING COUNT(o.id) > 1`)
|
|
23
|
+
.all();
|
|
24
|
+
removed = 0;
|
|
25
|
+
const del = conn.prepare(`DELETE FROM observations WHERE entity_id = ? AND id NOT IN (
|
|
26
|
+
SELECT MIN(id) FROM observations WHERE entity_id = ? GROUP BY content)`);
|
|
27
|
+
for (const row of affected)
|
|
28
|
+
removed += Number(del.run(row.id, row.id).changes);
|
|
29
|
+
if (removed > 0) {
|
|
30
|
+
rebuildFtsIndex(conn);
|
|
31
|
+
note(`removed ${removed} duplicate observation(s) from ${affected.length} session entit${affected.length === 1 ? 'y' : 'ies'} (written by 4.8.1 hooks).`);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
return removed;
|
|
36
|
+
}
|
|
37
|
+
const BASH_WRITE_SHAPES = [
|
|
38
|
+
/(?:^|[^<])>\s*"?([^\s"'>|&;]+)"?\s*<<\s*['"]?\w+['"]?/,
|
|
39
|
+
/\bcat\s*>\s*"?([^\s"'>|&;]+)"?/,
|
|
40
|
+
/\btee\s+(?:-a\s+)?"?([^\s"'>|&;]+)"?/,
|
|
41
|
+
/\bsed\s+-i(?:\s+'')?\s+(?:'[^']*'|"[^"]*")\s+"?([^\s"'>|&;]+)"?/,
|
|
42
|
+
/Path\(\s*['"]([^'"]+)['"]\s*\)\s*\.write_text\(/,
|
|
43
|
+
/writeFileSync\(\s*['"]([^'"]+)['"]/,
|
|
44
|
+
];
|
|
45
|
+
export function bashWritesFiles(command) {
|
|
46
|
+
for (const re of BASH_WRITE_SHAPES) {
|
|
47
|
+
for (const m of command.matchAll(new RegExp(re.source, 'g'))) {
|
|
48
|
+
if (m[1] && !m[1].startsWith('/dev/') && !m[1].startsWith('/tmp/'))
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
export function retractZeroEditClaims(db) {
|
|
55
|
+
let rewritten = -1;
|
|
56
|
+
runOnceMigration(db, {
|
|
57
|
+
key: ZERO_EDIT_RETRACT_KEY,
|
|
58
|
+
version: 1,
|
|
59
|
+
describe: 'session zero-edit retraction',
|
|
60
|
+
migrate: (conn) => {
|
|
61
|
+
const candidates = conn
|
|
62
|
+
.prepare(`SELECT o.id, o.content, o.entity_id FROM observations o JOIN entities e ON e.id = o.entity_id
|
|
63
|
+
WHERE e.name LIKE 'session-%-summary'
|
|
64
|
+
AND o.content LIKE 'Significant session:%${ZERO_EDITS}%'`)
|
|
65
|
+
.all();
|
|
66
|
+
const commands = conn.prepare("SELECT content FROM observations WHERE entity_id = ? AND content LIKE 'Command:%'");
|
|
67
|
+
const update = conn.prepare('UPDATE observations SET content = ? WHERE id = ?');
|
|
68
|
+
rewritten = 0;
|
|
69
|
+
for (const row of candidates) {
|
|
70
|
+
const cmds = commands.all(row.entity_id);
|
|
71
|
+
if (!cmds.some((c) => bashWritesFiles(c.content)))
|
|
72
|
+
continue;
|
|
73
|
+
update.run(row.content.replace(ZERO_EDITS, ZERO_EDITS_RETRACTED), row.id);
|
|
74
|
+
rewritten += 1;
|
|
75
|
+
}
|
|
76
|
+
if (rewritten > 0) {
|
|
77
|
+
rebuildFtsIndex(conn);
|
|
78
|
+
note(`retracted "0 files edited" on ${rewritten} session summar${rewritten === 1 ? 'y' : 'ies'} that recorded a Bash write.`);
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
return rewritten;
|
|
83
|
+
}
|
|
84
|
+
function groupLessons(rows) {
|
|
85
|
+
const groups = [];
|
|
86
|
+
for (const row of rows) {
|
|
87
|
+
if (row.content.startsWith('Error: ')) {
|
|
88
|
+
groups.push({ error: row.content.slice('Error: '.length), rows: [row] });
|
|
89
|
+
}
|
|
90
|
+
else if (groups.length > 0) {
|
|
91
|
+
groups[groups.length - 1].rows.push(row);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return groups;
|
|
95
|
+
}
|
|
96
|
+
export function splitFusedLessons(db, deps) {
|
|
97
|
+
let moved = -1;
|
|
98
|
+
runOnceMigration(db, {
|
|
99
|
+
key: FUSED_LESSON_SPLIT_KEY,
|
|
100
|
+
version: 1,
|
|
101
|
+
describe: 'fused lesson split',
|
|
102
|
+
migrate: (conn) => {
|
|
103
|
+
const buckets = conn
|
|
104
|
+
.prepare(`SELECT e.id, e.name, e.type, e.namespace, e.confidence, e.metadata
|
|
105
|
+
FROM entities e
|
|
106
|
+
WHERE e.type = 'lesson_learned' AND e.name LIKE 'lesson-%-other'
|
|
107
|
+
AND EXISTS (SELECT 1 FROM tags t WHERE t.entity_id = e.id AND t.tag = 'source:explicit')`)
|
|
108
|
+
.all();
|
|
109
|
+
const tagsOf = conn.prepare('SELECT tag FROM tags WHERE entity_id = ?');
|
|
110
|
+
const obsOf = conn.prepare('SELECT id, content, created_at FROM observations WHERE entity_id = ? ORDER BY id');
|
|
111
|
+
const findTarget = conn.prepare('SELECT id, status FROM entities WHERE name = ?');
|
|
112
|
+
const revive = conn.prepare("UPDATE entities SET status = 'active' WHERE id = ?");
|
|
113
|
+
const insertEntity = conn.prepare(`INSERT INTO entities (name, type, created_at, metadata, status, confidence, namespace, title)
|
|
114
|
+
VALUES (?, ?, ?, ?, 'active', ?, ?, ?)`);
|
|
115
|
+
const insertTag = conn.prepare('INSERT OR IGNORE INTO tags (entity_id, tag) VALUES (?, ?)');
|
|
116
|
+
const moveRow = conn.prepare('UPDATE observations SET entity_id = ? WHERE id = ?');
|
|
117
|
+
const emptied = 'NOT EXISTS (SELECT 1 FROM observations WHERE entity_id = ?)';
|
|
118
|
+
const dropExplicit = conn.prepare(`DELETE FROM tags WHERE entity_id = ? AND tag = 'source:explicit' AND ${emptied}`);
|
|
119
|
+
const archive = conn.prepare(`UPDATE entities SET status = 'archived' WHERE id = ? AND ${emptied}`);
|
|
120
|
+
moved = 0;
|
|
121
|
+
let bucketsTouched = 0;
|
|
122
|
+
for (const bucket of buckets) {
|
|
123
|
+
const groups = groupLessons(obsOf.all(bucket.id));
|
|
124
|
+
if (groups.length === 0)
|
|
125
|
+
continue;
|
|
126
|
+
const tags = tagsOf.all(bucket.id).map((t) => t.tag);
|
|
127
|
+
const project = tags.find((t) => t.startsWith('project:'))?.slice('project:'.length) ??
|
|
128
|
+
bucket.name.slice('lesson-'.length, -'-other'.length);
|
|
129
|
+
let inherited = {};
|
|
130
|
+
try {
|
|
131
|
+
const parsed = bucket.metadata ? JSON.parse(bucket.metadata) : {};
|
|
132
|
+
if (parsed && typeof parsed === 'object' && !Array.isArray(parsed))
|
|
133
|
+
inherited = parsed;
|
|
134
|
+
}
|
|
135
|
+
catch { }
|
|
136
|
+
const severities = tags.filter((t) => t.startsWith('severity:'));
|
|
137
|
+
const carried = tags.filter((t) => !t.startsWith('severity:') && !t.startsWith('source:'));
|
|
138
|
+
if (severities.length === 1)
|
|
139
|
+
carried.push(severities[0]);
|
|
140
|
+
if (!tags.includes('source:auto-learned'))
|
|
141
|
+
carried.push('source:explicit');
|
|
142
|
+
let movedFromBucket = 0;
|
|
143
|
+
for (const group of groups) {
|
|
144
|
+
const slug = lessonSlug(group.error);
|
|
145
|
+
if (slug === 'other')
|
|
146
|
+
continue;
|
|
147
|
+
const name = `lesson-${project}-${slug}`;
|
|
148
|
+
if (name === bucket.name)
|
|
149
|
+
continue;
|
|
150
|
+
let target = findTarget.get(name);
|
|
151
|
+
if (target) {
|
|
152
|
+
if (target.status !== 'active')
|
|
153
|
+
revive.run(target.id);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
const contents = group.rows.map((o) => o.content);
|
|
157
|
+
const title = deps.deriveTitle(bucket.type, contents);
|
|
158
|
+
const metadata = {
|
|
159
|
+
...inherited,
|
|
160
|
+
split_from: bucket.name,
|
|
161
|
+
signal_score: computeSignalScore({ type: bucket.type, name, observations: contents, tags: carried }),
|
|
162
|
+
};
|
|
163
|
+
if (title)
|
|
164
|
+
metadata.title_source = 'heuristic';
|
|
165
|
+
else
|
|
166
|
+
delete metadata.title_source;
|
|
167
|
+
delete metadata.guard;
|
|
168
|
+
delete metadata.evidence_for;
|
|
169
|
+
delete metadata.previous_namespace;
|
|
170
|
+
const inserted = insertEntity.run(name, bucket.type, group.rows[0].created_at, JSON.stringify(metadata), bucket.confidence, bucket.namespace, title);
|
|
171
|
+
target = { id: Number(inserted.lastInsertRowid), status: 'active' };
|
|
172
|
+
for (const tag of carried)
|
|
173
|
+
insertTag.run(target.id, tag);
|
|
174
|
+
}
|
|
175
|
+
for (const row of group.rows)
|
|
176
|
+
moveRow.run(target.id, row.id);
|
|
177
|
+
moved += 1;
|
|
178
|
+
movedFromBucket += 1;
|
|
179
|
+
}
|
|
180
|
+
dropExplicit.run(bucket.id, bucket.id);
|
|
181
|
+
archive.run(bucket.id, bucket.id);
|
|
182
|
+
if (movedFromBucket > 0)
|
|
183
|
+
bucketsTouched += 1;
|
|
184
|
+
}
|
|
185
|
+
if (moved > 0) {
|
|
186
|
+
rebuildFtsIndex(conn);
|
|
187
|
+
deps.markReindexOwed(conn);
|
|
188
|
+
note(`moved ${moved} lesson(s) out of ${bucketsTouched} "-other" bucket(s) into their own entities; run 'memesh reindex' to refresh their vectors.`);
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
return moved;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=graph-repairs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-repairs.js","sourceRoot":"","sources":["../../src/storage/graph-repairs.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/transports/http/server.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/transports/http/server.ts"],"names":[],"mappings":";AAmDA,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAkB,MAAM,6BAA6B,CAAC;AAiBjG,QAAA,MAAM,GAAG,6CAAY,CAAC;AA8CtB,wBAAgB,iBAAiB,CAAC,GAAG,EAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAG/D;AA82CD,wBAAgB,WAAW,CACzB,IAAI,SAAO,EACX,IAAI,SAAO,EACX,IAAI,CAAC,EAAE;IACL,WAAW,CAAC,EAAE,OAAO,CAAC;IAUtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,eAAe,CAAC,EAAE,OAAO,cAAc,CAAC;IACxC,mBAAmB,CAAC,EAAE,OAAO,kBAAkB,CAAC;CACjD,GACA,UAAU,CAAC,OAAO,GAAG,CAAC,MAAM,CAAC,CA8I/B;AAID,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAElE;AAwBD,OAAO,EAAE,GAAG,EAAE,CAAC"}
|
|
@@ -3,10 +3,10 @@ import express from 'express';
|
|
|
3
3
|
import { rateLimit } from 'express-rate-limit';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { randomBytes, timingSafeEqual } from 'crypto';
|
|
6
|
-
import { openDatabase, closeDatabase, getDatabase } from '../../db.js';
|
|
7
|
-
import { remember, recallWithConflicts, forget, exportMemories, importMemories, learn } from '../../core/operations.js';
|
|
6
|
+
import { openDatabase, closeDatabase, getDatabase, getStoredEmbeddingDimension, getPendingReindexInfo, readVectorGeneration, } from '../../db.js';
|
|
7
|
+
import { remember, recallWithConflicts, forget, exportMemories, importMemories, learn, reindex, countMissingVectors, } from '../../core/operations.js';
|
|
8
8
|
import { KnowledgeGraph } from '../../knowledge-graph.js';
|
|
9
|
-
import { logCapabilities, readConfig, updateConfig, detectCapabilities } from '../../core/config.js';
|
|
9
|
+
import { logCapabilities, readConfig, updateConfig, detectCapabilities, getEmbeddingDimension, } from '../../core/config.js';
|
|
10
10
|
import { languageValueError } from '../../core/output-language.js';
|
|
11
11
|
import { computePatterns } from '../../core/patterns.js';
|
|
12
12
|
import { computeAnalytics, computePmAnalytics } from '../../core/analytics.js';
|
|
@@ -241,8 +241,21 @@ app.get('/dashboard', (_req, res) => {
|
|
|
241
241
|
app.get('/v1/health', (_req, res) => {
|
|
242
242
|
try {
|
|
243
243
|
const db = getDatabase();
|
|
244
|
-
const count = db.prepare(
|
|
245
|
-
|
|
244
|
+
const count = db.prepare(`
|
|
245
|
+
SELECT
|
|
246
|
+
COUNT(*) AS c,
|
|
247
|
+
SUM(CASE WHEN json_extract(metadata, '$.demo') = 1 THEN 1 ELSE 0 END) AS demo_c
|
|
248
|
+
FROM entities
|
|
249
|
+
`).get();
|
|
250
|
+
res.json({
|
|
251
|
+
success: true,
|
|
252
|
+
data: {
|
|
253
|
+
status: 'ok',
|
|
254
|
+
version: packageVersion,
|
|
255
|
+
entity_count: count.c,
|
|
256
|
+
demo_entity_count: count.demo_c ?? 0,
|
|
257
|
+
},
|
|
258
|
+
});
|
|
246
259
|
}
|
|
247
260
|
catch (err) {
|
|
248
261
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -439,6 +452,10 @@ const ConfigBody = z.object({
|
|
|
439
452
|
apiKey: z.string().optional(),
|
|
440
453
|
keepKeyFrom: z.number().int().nonnegative().nullable().optional(),
|
|
441
454
|
})).optional(),
|
|
455
|
+
embedder: z.union([
|
|
456
|
+
z.object({ provider: z.enum(['openai', 'ollama']) }),
|
|
457
|
+
z.null(),
|
|
458
|
+
]).optional(),
|
|
442
459
|
autoCapture: z.boolean().optional(),
|
|
443
460
|
sessionLimit: z.number().int().min(1).max(100).optional(),
|
|
444
461
|
autoUpdate: z.enum(['off', 'patch', 'minor', 'major']).optional(),
|
|
@@ -451,6 +468,9 @@ const ConfigBody = z.object({
|
|
|
451
468
|
}).strict();
|
|
452
469
|
app.post('/v1/config', (req, res) => handlePost(ConfigBody, req, res, (data) => {
|
|
453
470
|
const before = readConfig();
|
|
471
|
+
if (data.embedder !== undefined && reindexJob?.state === 'running') {
|
|
472
|
+
throw new Error('The search index is being rebuilt. Wait for it to finish before changing the embedding provider.');
|
|
473
|
+
}
|
|
454
474
|
if (data.llm && data.llm.apiKey === API_KEY_MASK) {
|
|
455
475
|
if (before.llm && before.llm.provider === data.llm.provider && before.llm.apiKey) {
|
|
456
476
|
data.llm.apiKey = before.llm.apiKey;
|
|
@@ -463,17 +483,107 @@ app.post('/v1/config', (req, res) => handlePost(ConfigBody, req, res, (data) =>
|
|
|
463
483
|
data.llmFallbacks = preserveFallbackApiKeys(data.llmFallbacks, before.llmFallbacks);
|
|
464
484
|
}
|
|
465
485
|
const updated = updateConfig(data);
|
|
486
|
+
if (data.embedder && before.embedder?.provider !== data.embedder.provider) {
|
|
487
|
+
reindexJob = null;
|
|
488
|
+
}
|
|
466
489
|
return maskLlmSecrets(updated);
|
|
467
490
|
}));
|
|
491
|
+
let reindexJob = null;
|
|
492
|
+
function safeReindexDiagnostic(message) {
|
|
493
|
+
return redactUserPaths(redactSecrets(message));
|
|
494
|
+
}
|
|
495
|
+
function reindexStatus() {
|
|
496
|
+
const config = readConfig();
|
|
497
|
+
const embeddings = detectCapabilities(config).embeddings;
|
|
498
|
+
const configuredProvider = embeddings === 'openai' || embeddings === 'ollama'
|
|
499
|
+
? embeddings
|
|
500
|
+
: null;
|
|
501
|
+
const pendingReindex = getPendingReindexInfo();
|
|
502
|
+
const generationRead = readVectorGeneration();
|
|
503
|
+
const generation = generationRead.state === 'unreadable'
|
|
504
|
+
? { ...generationRead, detail: safeReindexDiagnostic(generationRead.detail) }
|
|
505
|
+
: generationRead;
|
|
506
|
+
const configuredDimension = getEmbeddingDimension(config);
|
|
507
|
+
const storedDimension = getStoredEmbeddingDimension();
|
|
508
|
+
const missingVectors = countMissingVectors(getDatabase());
|
|
509
|
+
const retryNeeded = pendingReindex !== null
|
|
510
|
+
|| generation.state !== 'none'
|
|
511
|
+
|| configuredDimension !== storedDimension
|
|
512
|
+
|| missingVectors > 0;
|
|
513
|
+
const status = reindexJob?.state === 'running'
|
|
514
|
+
? 'running'
|
|
515
|
+
: reindexJob?.state === 'failed'
|
|
516
|
+
? 'failed'
|
|
517
|
+
: retryNeeded
|
|
518
|
+
? 'retry-needed'
|
|
519
|
+
: reindexJob?.state === 'succeeded'
|
|
520
|
+
? 'succeeded'
|
|
521
|
+
: 'idle';
|
|
522
|
+
return {
|
|
523
|
+
status,
|
|
524
|
+
job: reindexJob === null ? null : {
|
|
525
|
+
id: reindexJob.id,
|
|
526
|
+
state: reindexJob.state,
|
|
527
|
+
processed: reindexJob.processed,
|
|
528
|
+
total: reindexJob.total,
|
|
529
|
+
startedAt: reindexJob.startedAt,
|
|
530
|
+
finishedAt: reindexJob.finishedAt,
|
|
531
|
+
},
|
|
532
|
+
configuredProvider,
|
|
533
|
+
configuredDimension,
|
|
534
|
+
storedDimension,
|
|
535
|
+
pendingReindex,
|
|
536
|
+
missingVectors,
|
|
537
|
+
generation,
|
|
538
|
+
result: reindexJob?.result ?? null,
|
|
539
|
+
error: reindexJob?.error ?? null,
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
app.get('/v1/reindex', (_req, res) => handleGet(res, reindexStatus));
|
|
543
|
+
app.post('/v1/reindex', (_req, res) => {
|
|
544
|
+
if (reindexJob?.state !== 'running') {
|
|
545
|
+
reindexJob = {
|
|
546
|
+
id: randomBytes(8).toString('hex'),
|
|
547
|
+
state: 'running',
|
|
548
|
+
processed: 0,
|
|
549
|
+
total: 0,
|
|
550
|
+
startedAt: new Date().toISOString(),
|
|
551
|
+
finishedAt: null,
|
|
552
|
+
result: null,
|
|
553
|
+
error: null,
|
|
554
|
+
};
|
|
555
|
+
const job = reindexJob;
|
|
556
|
+
void reindex({
|
|
557
|
+
onProgress: ({ processed, total }) => {
|
|
558
|
+
job.processed = processed;
|
|
559
|
+
job.total = total;
|
|
560
|
+
},
|
|
561
|
+
}).then((result) => {
|
|
562
|
+
job.result = result;
|
|
563
|
+
const incomplete = result.failed > 0 || result.generationSwapped === false;
|
|
564
|
+
job.state = incomplete ? 'failed' : 'succeeded';
|
|
565
|
+
if (incomplete) {
|
|
566
|
+
job.error = 'The new search index is incomplete. The previous index is still active; retry the rebuild.';
|
|
567
|
+
}
|
|
568
|
+
job.finishedAt = new Date().toISOString();
|
|
569
|
+
}).catch((err) => {
|
|
570
|
+
job.state = 'failed';
|
|
571
|
+
job.error = safeReindexDiagnostic(err instanceof Error ? err.message : 'The rebuild failed.');
|
|
572
|
+
job.finishedAt = new Date().toISOString();
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
res.status(202).json({ success: true, data: reindexStatus() });
|
|
576
|
+
});
|
|
468
577
|
const ConfigTestBody = z.object({
|
|
469
578
|
provider: z.enum(['anthropic', 'openai', 'ollama']),
|
|
470
579
|
apiKey: z.string().max(500).optional(),
|
|
471
580
|
host: z.string().max(500).optional(),
|
|
581
|
+
model: z.string().min(1).max(200).optional(),
|
|
472
582
|
fallbackIndex: z.number().int().nonnegative().optional(),
|
|
473
583
|
});
|
|
474
584
|
app.post('/v1/config/test', (req, res) => handlePost(ConfigTestBody, req, res, async (data) => {
|
|
475
585
|
const { probeProvider } = await import('../../core/llm-validator.js');
|
|
476
|
-
const { provider, host, fallbackIndex } = data;
|
|
586
|
+
const { provider, host, model, fallbackIndex } = data;
|
|
477
587
|
let { apiKey } = data;
|
|
478
588
|
if (!apiKey && (provider === 'anthropic' || provider === 'openai')) {
|
|
479
589
|
const existing = readConfig();
|
|
@@ -486,7 +596,7 @@ app.post('/v1/config/test', (req, res) => handlePost(ConfigTestBody, req, res, a
|
|
|
486
596
|
apiKey = existing.llm.apiKey;
|
|
487
597
|
}
|
|
488
598
|
}
|
|
489
|
-
return probeProvider(provider, apiKey, host);
|
|
599
|
+
return probeProvider(provider, apiKey, host, model);
|
|
490
600
|
}, { errorStatus: 500, errorCode: 'server.internal' }));
|
|
491
601
|
app.get('/v1/update-status', (req, res) => handleGet(res, async () => {
|
|
492
602
|
const cached = req.query.cached === '1' || req.query.cached === 'true';
|