ralph-hero-knowledge-index 0.1.13 → 0.1.15
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/plugin.json +1 -1
- package/.mcp.json +1 -1
- package/dist/db.d.ts +89 -3
- package/dist/db.js +202 -13
- package/dist/db.js.map +1 -1
- package/dist/format.d.ts +39 -0
- package/dist/format.js +40 -0
- package/dist/format.js.map +1 -0
- package/dist/graph-builder.d.ts +17 -0
- package/dist/graph-builder.js +35 -0
- package/dist/graph-builder.js.map +1 -0
- package/dist/graph-tools.d.ts +3 -0
- package/dist/graph-tools.js +474 -0
- package/dist/graph-tools.js.map +1 -0
- package/dist/hybrid-search.js +2 -1
- package/dist/hybrid-search.js.map +1 -1
- package/dist/index.js +90 -5
- package/dist/index.js.map +1 -1
- package/dist/parser.d.ts +13 -0
- package/dist/parser.js +36 -1
- package/dist/parser.js.map +1 -1
- package/dist/reindex.js +62 -11
- package/dist/reindex.js.map +1 -1
- package/dist/traverse.d.ts +1 -0
- package/dist/traverse.js +8 -4
- package/dist/traverse.js.map +1 -1
- package/dist/vector-search.d.ts +1 -0
- package/dist/vector-search.js +6 -0
- package/dist/vector-search.js.map +1 -1
- package/package.json +10 -1
- package/src/__tests__/db.test.ts +306 -1
- package/src/__tests__/format.test.ts +235 -0
- package/src/__tests__/graph-builder.test.ts +174 -0
- package/src/__tests__/graph-tools.test.ts +1015 -0
- package/src/__tests__/index.test.ts +6 -0
- package/src/__tests__/parser.test.ts +115 -1
- package/src/__tests__/reindex.test.ts +129 -3
- package/src/__tests__/traverse.test.ts +78 -0
- package/src/db.ts +312 -15
- package/src/format.ts +75 -0
- package/src/graph-builder.ts +66 -0
- package/src/graph-tools.ts +650 -0
- package/src/hybrid-search.ts +3 -2
- package/src/index.ts +100 -5
- package/src/parser.ts +53 -1
- package/src/reindex.ts +72 -12
- package/src/traverse.ts +11 -4
- package/src/vector-search.ts +7 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ralph-knowledge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "Knowledge graph for ralph-hero: semantic search, relationship traversal, and document indexing across thoughts/ documents. Optional companion to ralph-hero.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Chad Dubiel",
|
package/.mcp.json
CHANGED
package/dist/db.d.ts
CHANGED
|
@@ -1,30 +1,116 @@
|
|
|
1
1
|
import type { Database as DatabaseType } from "better-sqlite3";
|
|
2
2
|
export interface DocumentRow {
|
|
3
3
|
id: string;
|
|
4
|
-
path: string;
|
|
4
|
+
path: string | null;
|
|
5
5
|
title: string;
|
|
6
6
|
date: string | null;
|
|
7
7
|
type: string | null;
|
|
8
8
|
status: string | null;
|
|
9
9
|
githubIssue: number | null;
|
|
10
10
|
content: string;
|
|
11
|
+
isStub: number;
|
|
11
12
|
}
|
|
12
13
|
export interface RelationshipRow {
|
|
13
14
|
sourceId: string;
|
|
14
15
|
targetId: string;
|
|
15
16
|
type: string;
|
|
17
|
+
context: string | null;
|
|
18
|
+
}
|
|
19
|
+
export interface OutcomeEventInput {
|
|
20
|
+
eventType: string;
|
|
21
|
+
issueNumber: number;
|
|
22
|
+
sessionId?: string;
|
|
23
|
+
durationMs?: number;
|
|
24
|
+
verdict?: string;
|
|
25
|
+
componentArea?: string;
|
|
26
|
+
estimate?: string;
|
|
27
|
+
driftCount?: number;
|
|
28
|
+
model?: string;
|
|
29
|
+
agentType?: string;
|
|
30
|
+
iterationCount?: number;
|
|
31
|
+
payload?: Record<string, unknown>;
|
|
32
|
+
}
|
|
33
|
+
export interface OutcomeEventRow {
|
|
34
|
+
id: string;
|
|
35
|
+
eventType: string;
|
|
36
|
+
issueNumber: number;
|
|
37
|
+
sessionId: string | null;
|
|
38
|
+
timestamp: string;
|
|
39
|
+
durationMs: number | null;
|
|
40
|
+
verdict: string | null;
|
|
41
|
+
componentArea: string | null;
|
|
42
|
+
estimate: string | null;
|
|
43
|
+
driftCount: number | null;
|
|
44
|
+
model: string | null;
|
|
45
|
+
agentType: string | null;
|
|
46
|
+
iterationCount: number | null;
|
|
47
|
+
payload: string;
|
|
48
|
+
}
|
|
49
|
+
export interface SyncRecord {
|
|
50
|
+
path: string;
|
|
51
|
+
mtime: number;
|
|
52
|
+
indexed_at: number;
|
|
53
|
+
}
|
|
54
|
+
export interface OutcomeQueryParams {
|
|
55
|
+
issueNumber?: number;
|
|
56
|
+
eventType?: string;
|
|
57
|
+
componentArea?: string;
|
|
58
|
+
estimate?: string;
|
|
59
|
+
verdict?: string;
|
|
60
|
+
sessionId?: string;
|
|
61
|
+
since?: string;
|
|
62
|
+
limit?: number;
|
|
63
|
+
}
|
|
64
|
+
export interface OutcomeAggregate {
|
|
65
|
+
count: number;
|
|
66
|
+
avgDriftCount: number | null;
|
|
67
|
+
avgIterationCount: number | null;
|
|
68
|
+
verdictDistribution: Record<string, number>;
|
|
69
|
+
eventTypeDistribution: Record<string, number>;
|
|
70
|
+
topComponentAreas: Array<{
|
|
71
|
+
area: string;
|
|
72
|
+
count: number;
|
|
73
|
+
}>;
|
|
74
|
+
}
|
|
75
|
+
export interface OutcomeSummary {
|
|
76
|
+
totalEvents: number;
|
|
77
|
+
latestVerdict: string | null;
|
|
78
|
+
driftCount: number;
|
|
79
|
+
blockers: number;
|
|
80
|
+
eventsByType: Record<string, number>;
|
|
16
81
|
}
|
|
17
82
|
export declare class KnowledgeDB {
|
|
18
83
|
readonly db: DatabaseType;
|
|
19
84
|
constructor(dbPath: string);
|
|
20
85
|
private createSchema;
|
|
21
|
-
upsertDocument(doc: DocumentRow
|
|
86
|
+
upsertDocument(doc: Omit<DocumentRow, "isStub"> & {
|
|
87
|
+
isStub?: number;
|
|
88
|
+
}): void;
|
|
89
|
+
/**
|
|
90
|
+
* Creates a stub document for an unresolved wikilink target.
|
|
91
|
+
* Uses INSERT OR IGNORE so it never overwrites a real document.
|
|
92
|
+
*/
|
|
93
|
+
upsertStubDocument(id: string): void;
|
|
22
94
|
getDocument(id: string): DocumentRow | undefined;
|
|
23
95
|
setTags(docId: string, tags: string[]): void;
|
|
24
96
|
getTags(docId: string): string[];
|
|
25
|
-
addRelationship(sourceId: string, targetId: string, type: string): void;
|
|
97
|
+
addRelationship(sourceId: string, targetId: string, type: string, context?: string): void;
|
|
26
98
|
getRelationshipsFrom(sourceId: string): RelationshipRow[];
|
|
27
99
|
getRelationshipsTo(targetId: string): RelationshipRow[];
|
|
100
|
+
insertOutcomeEvent(input: OutcomeEventInput): {
|
|
101
|
+
id: string;
|
|
102
|
+
eventType: string;
|
|
103
|
+
issueNumber: number;
|
|
104
|
+
timestamp: string;
|
|
105
|
+
};
|
|
106
|
+
queryOutcomeEvents(params?: OutcomeQueryParams): OutcomeEventRow[];
|
|
107
|
+
aggregateOutcomeEvents(params?: OutcomeQueryParams): OutcomeAggregate;
|
|
108
|
+
getOutcomeSummary(issueNumber: number): OutcomeSummary | null;
|
|
109
|
+
getSyncRecord(path: string): SyncRecord | undefined;
|
|
110
|
+
upsertSyncRecord(path: string, mtime: number): void;
|
|
111
|
+
deleteSyncRecord(path: string): void;
|
|
112
|
+
getAllSyncPaths(): string[];
|
|
113
|
+
deleteDocument(id: string): void;
|
|
28
114
|
clearAll(): void;
|
|
29
115
|
close(): void;
|
|
30
116
|
}
|
package/dist/db.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import Database from "better-sqlite3";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
2
3
|
import { mkdirSync } from "node:fs";
|
|
3
4
|
import { dirname } from "node:path";
|
|
4
5
|
export class KnowledgeDB {
|
|
@@ -13,13 +14,14 @@ export class KnowledgeDB {
|
|
|
13
14
|
this.db.exec(`
|
|
14
15
|
CREATE TABLE IF NOT EXISTS documents (
|
|
15
16
|
id TEXT PRIMARY KEY,
|
|
16
|
-
path TEXT
|
|
17
|
+
path TEXT,
|
|
17
18
|
title TEXT,
|
|
18
19
|
date TEXT,
|
|
19
20
|
type TEXT,
|
|
20
21
|
status TEXT,
|
|
21
22
|
github_issue INTEGER,
|
|
22
|
-
content TEXT
|
|
23
|
+
content TEXT,
|
|
24
|
+
is_stub INTEGER DEFAULT 0
|
|
23
25
|
);
|
|
24
26
|
CREATE TABLE IF NOT EXISTS tags (
|
|
25
27
|
doc_id TEXT REFERENCES documents(id) ON DELETE CASCADE,
|
|
@@ -28,25 +30,65 @@ export class KnowledgeDB {
|
|
|
28
30
|
);
|
|
29
31
|
CREATE TABLE IF NOT EXISTS relationships (
|
|
30
32
|
source_id TEXT REFERENCES documents(id) ON DELETE CASCADE,
|
|
31
|
-
target_id TEXT,
|
|
32
|
-
type TEXT CHECK(type IN ('builds_on', 'tensions', 'superseded_by')),
|
|
33
|
+
target_id TEXT REFERENCES documents(id) ON DELETE CASCADE,
|
|
34
|
+
type TEXT CHECK(type IN ('builds_on', 'tensions', 'superseded_by', 'post_mortem', 'untyped')),
|
|
35
|
+
context TEXT,
|
|
33
36
|
PRIMARY KEY (source_id, target_id, type)
|
|
34
37
|
);
|
|
35
38
|
CREATE INDEX IF NOT EXISTS idx_rel_target ON relationships(target_id, type);
|
|
36
39
|
CREATE INDEX IF NOT EXISTS idx_tags_tag ON tags(tag);
|
|
40
|
+
|
|
41
|
+
CREATE TABLE IF NOT EXISTS outcome_events (
|
|
42
|
+
id TEXT PRIMARY KEY,
|
|
43
|
+
event_type TEXT NOT NULL,
|
|
44
|
+
issue_number INTEGER NOT NULL,
|
|
45
|
+
session_id TEXT,
|
|
46
|
+
timestamp TEXT NOT NULL,
|
|
47
|
+
duration_ms INTEGER,
|
|
48
|
+
verdict TEXT,
|
|
49
|
+
component_area TEXT,
|
|
50
|
+
estimate TEXT,
|
|
51
|
+
drift_count INTEGER,
|
|
52
|
+
model TEXT,
|
|
53
|
+
agent_type TEXT,
|
|
54
|
+
iteration_count INTEGER,
|
|
55
|
+
payload TEXT DEFAULT '{}'
|
|
56
|
+
);
|
|
57
|
+
CREATE INDEX IF NOT EXISTS idx_oe_type ON outcome_events(event_type);
|
|
58
|
+
CREATE INDEX IF NOT EXISTS idx_oe_issue ON outcome_events(issue_number);
|
|
59
|
+
CREATE INDEX IF NOT EXISTS idx_oe_component ON outcome_events(component_area);
|
|
60
|
+
CREATE INDEX IF NOT EXISTS idx_oe_timestamp ON outcome_events(timestamp);
|
|
61
|
+
CREATE INDEX IF NOT EXISTS idx_oe_session ON outcome_events(session_id);
|
|
62
|
+
CREATE INDEX IF NOT EXISTS idx_oe_type_component ON outcome_events(event_type, component_area);
|
|
63
|
+
|
|
64
|
+
CREATE TABLE IF NOT EXISTS sync (
|
|
65
|
+
path TEXT PRIMARY KEY,
|
|
66
|
+
mtime INTEGER NOT NULL,
|
|
67
|
+
indexed_at INTEGER NOT NULL
|
|
68
|
+
);
|
|
37
69
|
`);
|
|
38
70
|
}
|
|
39
71
|
upsertDocument(doc) {
|
|
40
72
|
this.db.prepare(`
|
|
41
|
-
INSERT INTO documents (id, path, title, date, type, status, github_issue, content)
|
|
42
|
-
VALUES (@id, @path, @title, @date, @type, @status, @githubIssue, @content)
|
|
73
|
+
INSERT INTO documents (id, path, title, date, type, status, github_issue, content, is_stub)
|
|
74
|
+
VALUES (@id, @path, @title, @date, @type, @status, @githubIssue, @content, 0)
|
|
43
75
|
ON CONFLICT(id) DO UPDATE SET
|
|
44
76
|
path = @path, title = @title, date = @date, type = @type,
|
|
45
|
-
status = @status, github_issue = @githubIssue, content = @content
|
|
77
|
+
status = @status, github_issue = @githubIssue, content = @content, is_stub = 0
|
|
46
78
|
`).run(doc);
|
|
47
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Creates a stub document for an unresolved wikilink target.
|
|
82
|
+
* Uses INSERT OR IGNORE so it never overwrites a real document.
|
|
83
|
+
*/
|
|
84
|
+
upsertStubDocument(id) {
|
|
85
|
+
this.db.prepare(`
|
|
86
|
+
INSERT OR IGNORE INTO documents (id, path, title, date, type, status, github_issue, content, is_stub)
|
|
87
|
+
VALUES (?, NULL, ?, NULL, NULL, NULL, NULL, '', 1)
|
|
88
|
+
`).run(id, id);
|
|
89
|
+
}
|
|
48
90
|
getDocument(id) {
|
|
49
|
-
return this.db.prepare(`SELECT id, path, title, date, type, status, github_issue AS githubIssue, content FROM documents WHERE id = ?`).get(id);
|
|
91
|
+
return this.db.prepare(`SELECT id, path, title, date, type, status, github_issue AS githubIssue, content, is_stub AS isStub FROM documents WHERE id = ?`).get(id);
|
|
50
92
|
}
|
|
51
93
|
setTags(docId, tags) {
|
|
52
94
|
this.db.prepare("DELETE FROM tags WHERE doc_id = ?").run(docId);
|
|
@@ -57,17 +99,164 @@ export class KnowledgeDB {
|
|
|
57
99
|
getTags(docId) {
|
|
58
100
|
return this.db.prepare("SELECT tag FROM tags WHERE doc_id = ? ORDER BY tag").all(docId).map(r => r.tag);
|
|
59
101
|
}
|
|
60
|
-
addRelationship(sourceId, targetId, type) {
|
|
61
|
-
this.db.prepare("INSERT OR IGNORE INTO relationships (source_id, target_id, type) VALUES (?, ?, ?)").run(sourceId, targetId, type);
|
|
102
|
+
addRelationship(sourceId, targetId, type, context) {
|
|
103
|
+
this.db.prepare("INSERT OR IGNORE INTO relationships (source_id, target_id, type, context) VALUES (?, ?, ?, ?)").run(sourceId, targetId, type, context ?? null);
|
|
62
104
|
}
|
|
63
105
|
getRelationshipsFrom(sourceId) {
|
|
64
|
-
return this.db.prepare("SELECT source_id AS sourceId, target_id AS targetId, type FROM relationships WHERE source_id = ?").all(sourceId);
|
|
106
|
+
return this.db.prepare("SELECT source_id AS sourceId, target_id AS targetId, type, context FROM relationships WHERE source_id = ?").all(sourceId);
|
|
65
107
|
}
|
|
66
108
|
getRelationshipsTo(targetId) {
|
|
67
|
-
return this.db.prepare("SELECT source_id AS sourceId, target_id AS targetId, type FROM relationships WHERE target_id = ?").all(targetId);
|
|
109
|
+
return this.db.prepare("SELECT source_id AS sourceId, target_id AS targetId, type, context FROM relationships WHERE target_id = ?").all(targetId);
|
|
110
|
+
}
|
|
111
|
+
insertOutcomeEvent(input) {
|
|
112
|
+
const id = randomUUID();
|
|
113
|
+
const timestamp = new Date().toISOString();
|
|
114
|
+
const payload = JSON.stringify(input.payload ?? {});
|
|
115
|
+
this.db.prepare(`
|
|
116
|
+
INSERT INTO outcome_events (id, event_type, issue_number, session_id, timestamp, duration_ms, verdict, component_area, estimate, drift_count, model, agent_type, iteration_count, payload)
|
|
117
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
118
|
+
`).run(id, input.eventType, input.issueNumber, input.sessionId ?? null, timestamp, input.durationMs ?? null, input.verdict ?? null, input.componentArea ?? null, input.estimate ?? null, input.driftCount ?? null, input.model ?? null, input.agentType ?? null, input.iterationCount ?? null, payload);
|
|
119
|
+
return { id, eventType: input.eventType, issueNumber: input.issueNumber, timestamp };
|
|
120
|
+
}
|
|
121
|
+
queryOutcomeEvents(params = {}) {
|
|
122
|
+
const conditions = [];
|
|
123
|
+
const values = [];
|
|
124
|
+
if (params.issueNumber !== undefined) {
|
|
125
|
+
conditions.push("issue_number = ?");
|
|
126
|
+
values.push(params.issueNumber);
|
|
127
|
+
}
|
|
128
|
+
if (params.eventType !== undefined) {
|
|
129
|
+
conditions.push("event_type = ?");
|
|
130
|
+
values.push(params.eventType);
|
|
131
|
+
}
|
|
132
|
+
if (params.componentArea !== undefined) {
|
|
133
|
+
conditions.push("component_area LIKE ?");
|
|
134
|
+
values.push(`${params.componentArea}%`);
|
|
135
|
+
}
|
|
136
|
+
if (params.estimate !== undefined) {
|
|
137
|
+
conditions.push("estimate = ?");
|
|
138
|
+
values.push(params.estimate);
|
|
139
|
+
}
|
|
140
|
+
if (params.verdict !== undefined) {
|
|
141
|
+
conditions.push("verdict = ?");
|
|
142
|
+
values.push(params.verdict);
|
|
143
|
+
}
|
|
144
|
+
if (params.sessionId !== undefined) {
|
|
145
|
+
conditions.push("session_id = ?");
|
|
146
|
+
values.push(params.sessionId);
|
|
147
|
+
}
|
|
148
|
+
if (params.since !== undefined) {
|
|
149
|
+
conditions.push("timestamp >= ?");
|
|
150
|
+
values.push(params.since);
|
|
151
|
+
}
|
|
152
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
153
|
+
const limit = params.limit ?? 50;
|
|
154
|
+
const sql = `
|
|
155
|
+
SELECT id, event_type AS eventType, issue_number AS issueNumber, session_id AS sessionId,
|
|
156
|
+
timestamp, duration_ms AS durationMs, verdict, component_area AS componentArea,
|
|
157
|
+
estimate, drift_count AS driftCount, model, agent_type AS agentType,
|
|
158
|
+
iteration_count AS iterationCount, payload
|
|
159
|
+
FROM outcome_events ${where}
|
|
160
|
+
ORDER BY timestamp DESC
|
|
161
|
+
LIMIT ?
|
|
162
|
+
`;
|
|
163
|
+
return this.db.prepare(sql).all(...values, limit);
|
|
164
|
+
}
|
|
165
|
+
aggregateOutcomeEvents(params = {}) {
|
|
166
|
+
// Override limit to aggregate over all matching events, not just the caller's limit
|
|
167
|
+
const rows = this.queryOutcomeEvents({ ...params, limit: undefined });
|
|
168
|
+
const verdictDistribution = {};
|
|
169
|
+
const eventTypeDistribution = {};
|
|
170
|
+
const componentCounts = {};
|
|
171
|
+
let driftSum = 0;
|
|
172
|
+
let driftCount = 0;
|
|
173
|
+
let iterSum = 0;
|
|
174
|
+
let iterCount = 0;
|
|
175
|
+
for (const row of rows) {
|
|
176
|
+
if (row.verdict !== null) {
|
|
177
|
+
verdictDistribution[row.verdict] = (verdictDistribution[row.verdict] ?? 0) + 1;
|
|
178
|
+
}
|
|
179
|
+
eventTypeDistribution[row.eventType] = (eventTypeDistribution[row.eventType] ?? 0) + 1;
|
|
180
|
+
if (row.componentArea !== null) {
|
|
181
|
+
componentCounts[row.componentArea] = (componentCounts[row.componentArea] ?? 0) + 1;
|
|
182
|
+
}
|
|
183
|
+
if (row.driftCount !== null) {
|
|
184
|
+
driftSum += row.driftCount;
|
|
185
|
+
driftCount++;
|
|
186
|
+
}
|
|
187
|
+
if (row.iterationCount !== null) {
|
|
188
|
+
iterSum += row.iterationCount;
|
|
189
|
+
iterCount++;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const topComponentAreas = Object.entries(componentCounts)
|
|
193
|
+
.map(([area, count]) => ({ area, count }))
|
|
194
|
+
.sort((a, b) => b.count - a.count)
|
|
195
|
+
.slice(0, 10);
|
|
196
|
+
return {
|
|
197
|
+
count: rows.length,
|
|
198
|
+
avgDriftCount: driftCount > 0 ? driftSum / driftCount : null,
|
|
199
|
+
avgIterationCount: iterCount > 0 ? iterSum / iterCount : null,
|
|
200
|
+
verdictDistribution,
|
|
201
|
+
eventTypeDistribution,
|
|
202
|
+
topComponentAreas,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
getOutcomeSummary(issueNumber) {
|
|
206
|
+
const rows = this.queryOutcomeEvents({ issueNumber, limit: 10000 });
|
|
207
|
+
if (rows.length === 0)
|
|
208
|
+
return null;
|
|
209
|
+
const eventsByType = {};
|
|
210
|
+
let driftCount = 0;
|
|
211
|
+
let blockers = 0;
|
|
212
|
+
let latestVerdict = null;
|
|
213
|
+
for (const row of rows) {
|
|
214
|
+
eventsByType[row.eventType] = (eventsByType[row.eventType] ?? 0) + 1;
|
|
215
|
+
if (row.driftCount !== null) {
|
|
216
|
+
driftCount += row.driftCount;
|
|
217
|
+
}
|
|
218
|
+
if (row.eventType === "blocker_recorded") {
|
|
219
|
+
blockers++;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// Rows are ordered by timestamp DESC, so first row has the latest verdict
|
|
223
|
+
for (const row of rows) {
|
|
224
|
+
if (row.verdict !== null) {
|
|
225
|
+
latestVerdict = row.verdict;
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
totalEvents: rows.length,
|
|
231
|
+
latestVerdict,
|
|
232
|
+
driftCount,
|
|
233
|
+
blockers,
|
|
234
|
+
eventsByType,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
getSyncRecord(path) {
|
|
238
|
+
return this.db.prepare("SELECT path, mtime, indexed_at AS indexed_at FROM sync WHERE path = ?").get(path);
|
|
239
|
+
}
|
|
240
|
+
upsertSyncRecord(path, mtime) {
|
|
241
|
+
const indexedAt = Date.now();
|
|
242
|
+
this.db.prepare(`
|
|
243
|
+
INSERT INTO sync (path, mtime, indexed_at)
|
|
244
|
+
VALUES (?, ?, ?)
|
|
245
|
+
ON CONFLICT(path) DO UPDATE SET mtime = ?, indexed_at = ?
|
|
246
|
+
`).run(path, mtime, indexedAt, mtime, indexedAt);
|
|
247
|
+
}
|
|
248
|
+
deleteSyncRecord(path) {
|
|
249
|
+
this.db.prepare("DELETE FROM sync WHERE path = ?").run(path);
|
|
250
|
+
}
|
|
251
|
+
getAllSyncPaths() {
|
|
252
|
+
return this.db.prepare("SELECT path FROM sync").all().map(r => r.path);
|
|
253
|
+
}
|
|
254
|
+
deleteDocument(id) {
|
|
255
|
+
this.db.prepare("DELETE FROM documents WHERE id = ?").run(id);
|
|
68
256
|
}
|
|
69
257
|
clearAll() {
|
|
70
|
-
|
|
258
|
+
// outcome_events is intentionally NOT cleared — outcome data is preserved across rebuilds
|
|
259
|
+
this.db.exec("DELETE FROM relationships; DELETE FROM tags; DELETE FROM documents; DELETE FROM sync;");
|
|
71
260
|
}
|
|
72
261
|
close() {
|
|
73
262
|
this.db.close();
|
package/dist/db.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
|
package/dist/format.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SearchResult } from "./search.js";
|
|
2
|
+
import type { TraverseResult } from "./traverse.js";
|
|
3
|
+
export interface EnrichedSearchResult extends SearchResult {
|
|
4
|
+
tags: string[];
|
|
5
|
+
outcomes_summary?: unknown;
|
|
6
|
+
}
|
|
7
|
+
export interface BriefSearchResult {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
type: string | null;
|
|
11
|
+
date: string | null;
|
|
12
|
+
tags: string[];
|
|
13
|
+
score: number;
|
|
14
|
+
}
|
|
15
|
+
export interface BriefTraverseResult {
|
|
16
|
+
sourceId: string;
|
|
17
|
+
targetId: string;
|
|
18
|
+
type: string;
|
|
19
|
+
depth: number;
|
|
20
|
+
doc: {
|
|
21
|
+
title: string;
|
|
22
|
+
} | null;
|
|
23
|
+
tags: string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Format search results for return to the caller.
|
|
27
|
+
*
|
|
28
|
+
* brief=false (default): Returns the full enriched result objects unchanged.
|
|
29
|
+
* brief=true: Returns lightweight objects with id, title, type, date, tags, score only.
|
|
30
|
+
* Strips snippet, path, status, and outcomes_summary.
|
|
31
|
+
*/
|
|
32
|
+
export declare function formatSearchResults(results: EnrichedSearchResult[], brief: boolean): EnrichedSearchResult[] | BriefSearchResult[];
|
|
33
|
+
/**
|
|
34
|
+
* Format traverse results for return to the caller.
|
|
35
|
+
*
|
|
36
|
+
* brief=false (default): Returns the original TraverseResult objects unchanged (no tags added).
|
|
37
|
+
* brief=true: Strips doc to { title } only and adds tags array per hop target.
|
|
38
|
+
*/
|
|
39
|
+
export declare function formatTraverseResults(results: TraverseResult[], getTagsFn: (id: string) => string[], brief: boolean): TraverseResult[] | BriefTraverseResult[];
|
package/dist/format.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format search results for return to the caller.
|
|
3
|
+
*
|
|
4
|
+
* brief=false (default): Returns the full enriched result objects unchanged.
|
|
5
|
+
* brief=true: Returns lightweight objects with id, title, type, date, tags, score only.
|
|
6
|
+
* Strips snippet, path, status, and outcomes_summary.
|
|
7
|
+
*/
|
|
8
|
+
export function formatSearchResults(results, brief) {
|
|
9
|
+
if (!brief) {
|
|
10
|
+
return results;
|
|
11
|
+
}
|
|
12
|
+
return results.map((r) => ({
|
|
13
|
+
id: r.id,
|
|
14
|
+
title: r.title,
|
|
15
|
+
type: r.type,
|
|
16
|
+
date: r.date,
|
|
17
|
+
tags: r.tags,
|
|
18
|
+
score: r.score,
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Format traverse results for return to the caller.
|
|
23
|
+
*
|
|
24
|
+
* brief=false (default): Returns the original TraverseResult objects unchanged (no tags added).
|
|
25
|
+
* brief=true: Strips doc to { title } only and adds tags array per hop target.
|
|
26
|
+
*/
|
|
27
|
+
export function formatTraverseResults(results, getTagsFn, brief) {
|
|
28
|
+
if (!brief) {
|
|
29
|
+
return results;
|
|
30
|
+
}
|
|
31
|
+
return results.map((r) => ({
|
|
32
|
+
sourceId: r.sourceId,
|
|
33
|
+
targetId: r.targetId,
|
|
34
|
+
type: r.type,
|
|
35
|
+
depth: r.depth,
|
|
36
|
+
doc: r.doc != null ? { title: r.doc.title } : null,
|
|
37
|
+
tags: getTagsFn(r.targetId),
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AA0BA;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAA+B,EAC/B,KAAc;IAEd,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAqB,EAAE,CAAC,CAAC;QAC5C,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,KAAK;KACf,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAyB,EACzB,SAAmC,EACnC,KAAc;IAEd,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAuB,EAAE,CAAC,CAAC;QAC9C,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI;QAClD,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;KAC5B,CAAC,CAAC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MultiDirectedGraph } from "graphology";
|
|
2
|
+
import type { KnowledgeDB } from "./db.js";
|
|
3
|
+
export interface NodeAttributes {
|
|
4
|
+
title: string;
|
|
5
|
+
type: string | null;
|
|
6
|
+
date: string | null;
|
|
7
|
+
status: string | null;
|
|
8
|
+
}
|
|
9
|
+
export interface EdgeAttributes {
|
|
10
|
+
type: string;
|
|
11
|
+
}
|
|
12
|
+
export type KnowledgeGraph = MultiDirectedGraph<NodeAttributes, EdgeAttributes>;
|
|
13
|
+
export declare class GraphBuilder {
|
|
14
|
+
private readonly db;
|
|
15
|
+
constructor(db: KnowledgeDB);
|
|
16
|
+
buildGraph(): KnowledgeGraph;
|
|
17
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { MultiDirectedGraph } from "graphology";
|
|
2
|
+
export class GraphBuilder {
|
|
3
|
+
db;
|
|
4
|
+
constructor(db) {
|
|
5
|
+
this.db = db;
|
|
6
|
+
}
|
|
7
|
+
buildGraph() {
|
|
8
|
+
const graph = new MultiDirectedGraph();
|
|
9
|
+
// Load all documents and add as nodes
|
|
10
|
+
const docs = this.db.db
|
|
11
|
+
.prepare("SELECT id, title, date, type, status FROM documents WHERE is_stub = 0 OR is_stub IS NULL")
|
|
12
|
+
.all();
|
|
13
|
+
for (const doc of docs) {
|
|
14
|
+
graph.addNode(doc.id, {
|
|
15
|
+
title: doc.title,
|
|
16
|
+
type: doc.type,
|
|
17
|
+
date: doc.date,
|
|
18
|
+
status: doc.status,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
// Load all relationships and add as directed edges
|
|
22
|
+
const rels = this.db.db
|
|
23
|
+
.prepare("SELECT source_id, target_id, type FROM relationships")
|
|
24
|
+
.all();
|
|
25
|
+
for (const rel of rels) {
|
|
26
|
+
// Defensively skip edges where source or target node does not exist
|
|
27
|
+
if (!graph.hasNode(rel.source_id) || !graph.hasNode(rel.target_id)) {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
graph.addDirectedEdge(rel.source_id, rel.target_id, { type: rel.type });
|
|
31
|
+
}
|
|
32
|
+
return graph;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=graph-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-builder.js","sourceRoot":"","sources":["../src/graph-builder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAgBhD,MAAM,OAAO,YAAY;IACN,EAAE,CAAc;IAEjC,YAAY,EAAe;QACzB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IACf,CAAC;IAED,UAAU;QACR,MAAM,KAAK,GAAmB,IAAI,kBAAkB,EAAkC,CAAC;QAEvF,sCAAsC;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE;aACpB,OAAO,CAAC,0FAA0F,CAAC;aACnG,GAAG,EAMJ,CAAC;QAEH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE;gBACpB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,MAAM,EAAE,GAAG,CAAC,MAAM;aACnB,CAAC,CAAC;QACL,CAAC;QAED,mDAAmD;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,EAAE;aACpB,OAAO,CAAC,sDAAsD,CAAC;aAC/D,GAAG,EAIJ,CAAC;QAEH,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,oEAAoE;YACpE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;gBACnE,SAAS;YACX,CAAC;YACD,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1E,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
|