@pcircle/memesh 2.11.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +153 -52
- package/dist/cli/assets/d3.v7.min.js +2 -0
- package/dist/cli/view.d.ts +1 -0
- package/dist/cli/view.d.ts.map +1 -1
- package/dist/cli/view.js +2198 -10
- package/dist/cli/view.js.map +1 -1
- package/dist/core/config.d.ts +33 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +70 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/extractor.d.ts +26 -0
- package/dist/core/extractor.d.ts.map +1 -0
- package/dist/core/extractor.js +106 -0
- package/dist/core/extractor.js.map +1 -0
- package/dist/core/lifecycle.d.ts +9 -0
- package/dist/core/lifecycle.d.ts.map +1 -0
- package/dist/core/lifecycle.js +51 -0
- package/dist/core/lifecycle.js.map +1 -0
- package/dist/core/operations.d.ts +9 -0
- package/dist/core/operations.d.ts.map +1 -0
- package/dist/core/operations.js +342 -0
- package/dist/core/operations.js.map +1 -0
- package/dist/core/query-expander.d.ts +4 -0
- package/dist/core/query-expander.d.ts.map +1 -0
- package/dist/core/query-expander.js +114 -0
- package/dist/core/query-expander.js.map +1 -0
- package/dist/core/schema-export.d.ts +2 -0
- package/dist/core/schema-export.d.ts.map +1 -0
- package/dist/core/schema-export.js +67 -0
- package/dist/core/schema-export.js.map +1 -0
- package/dist/core/scoring.d.ts +25 -0
- package/dist/core/scoring.d.ts.map +1 -0
- package/dist/core/scoring.js +40 -0
- package/dist/core/scoring.js.map +1 -0
- package/dist/core/types.d.ts +124 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/version-check.d.ts +10 -0
- package/dist/core/version-check.d.ts.map +1 -0
- package/dist/core/version-check.js +44 -0
- package/dist/core/version-check.js.map +1 -0
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +33 -0
- package/dist/db.js.map +1 -1
- package/dist/knowledge-graph.d.ts +16 -30
- package/dist/knowledge-graph.d.ts.map +1 -1
- package/dist/knowledge-graph.js +205 -24
- package/dist/knowledge-graph.js.map +1 -1
- package/dist/mcp/server.js +8 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +1 -92
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +1 -182
- package/dist/mcp/tools.js.map +1 -1
- package/dist/transports/cli/cli.d.ts +3 -0
- package/dist/transports/cli/cli.d.ts.map +1 -0
- package/dist/transports/cli/cli.js +378 -0
- package/dist/transports/cli/cli.js.map +1 -0
- package/dist/transports/http/server.d.ts +5 -0
- package/dist/transports/http/server.d.ts.map +1 -0
- package/dist/transports/http/server.js +314 -0
- package/dist/transports/http/server.js.map +1 -0
- package/dist/transports/mcp/handlers.d.ts +184 -0
- package/dist/transports/mcp/handlers.d.ts.map +1 -0
- package/dist/transports/mcp/handlers.js +271 -0
- package/dist/transports/mcp/handlers.js.map +1 -0
- package/hooks/hooks.json +24 -0
- package/package.json +27 -9
- package/plugin.json +4 -4
- package/scripts/hooks/post-commit.js +35 -6
- package/scripts/hooks/pre-compact.js +198 -0
- package/scripts/hooks/session-start.js +73 -25
- package/scripts/hooks/session-summary.js +255 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
export interface Entity {
|
|
2
|
+
id: number;
|
|
3
|
+
name: string;
|
|
4
|
+
type: string;
|
|
5
|
+
created_at: string;
|
|
6
|
+
metadata?: any;
|
|
7
|
+
observations: string[];
|
|
8
|
+
tags: string[];
|
|
9
|
+
relations?: Relation[];
|
|
10
|
+
archived?: boolean;
|
|
11
|
+
access_count?: number;
|
|
12
|
+
last_accessed_at?: string;
|
|
13
|
+
confidence?: number;
|
|
14
|
+
valid_from?: string;
|
|
15
|
+
valid_until?: string;
|
|
16
|
+
namespace?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface Relation {
|
|
19
|
+
from: string;
|
|
20
|
+
to: string;
|
|
21
|
+
type: string;
|
|
22
|
+
metadata?: any;
|
|
23
|
+
}
|
|
24
|
+
export interface CreateEntityInput {
|
|
25
|
+
name: string;
|
|
26
|
+
type: string;
|
|
27
|
+
observations?: string[];
|
|
28
|
+
tags?: string[];
|
|
29
|
+
metadata?: any;
|
|
30
|
+
namespace?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface SearchOptions {
|
|
33
|
+
tag?: string;
|
|
34
|
+
limit?: number;
|
|
35
|
+
includeArchived?: boolean;
|
|
36
|
+
namespace?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface RememberInput {
|
|
39
|
+
name: string;
|
|
40
|
+
type: string;
|
|
41
|
+
observations?: string[];
|
|
42
|
+
tags?: string[];
|
|
43
|
+
relations?: Array<{
|
|
44
|
+
to: string;
|
|
45
|
+
type: string;
|
|
46
|
+
}>;
|
|
47
|
+
namespace?: string;
|
|
48
|
+
}
|
|
49
|
+
export interface RecallInput {
|
|
50
|
+
query?: string;
|
|
51
|
+
tag?: string;
|
|
52
|
+
limit?: number;
|
|
53
|
+
include_archived?: boolean;
|
|
54
|
+
namespace?: string;
|
|
55
|
+
cross_project?: boolean;
|
|
56
|
+
}
|
|
57
|
+
export interface ForgetInput {
|
|
58
|
+
name: string;
|
|
59
|
+
observation?: string;
|
|
60
|
+
}
|
|
61
|
+
export interface RememberResult {
|
|
62
|
+
stored: boolean;
|
|
63
|
+
entityId: number;
|
|
64
|
+
name: string;
|
|
65
|
+
type: string;
|
|
66
|
+
observations: number;
|
|
67
|
+
tags: number;
|
|
68
|
+
relations: number;
|
|
69
|
+
superseded?: string[];
|
|
70
|
+
relationErrors?: string[];
|
|
71
|
+
}
|
|
72
|
+
export interface ForgetResult {
|
|
73
|
+
archived?: boolean;
|
|
74
|
+
name?: string;
|
|
75
|
+
message?: string;
|
|
76
|
+
observation_removed?: boolean;
|
|
77
|
+
observation?: string;
|
|
78
|
+
remaining_observations?: number;
|
|
79
|
+
}
|
|
80
|
+
export interface ConsolidateInput {
|
|
81
|
+
name?: string;
|
|
82
|
+
tag?: string;
|
|
83
|
+
min_observations?: number;
|
|
84
|
+
}
|
|
85
|
+
export interface ConsolidateResult {
|
|
86
|
+
consolidated: number;
|
|
87
|
+
entities_processed: string[];
|
|
88
|
+
observations_before: number;
|
|
89
|
+
observations_after: number;
|
|
90
|
+
error?: string;
|
|
91
|
+
}
|
|
92
|
+
export interface ExportInput {
|
|
93
|
+
tag?: string;
|
|
94
|
+
namespace?: string;
|
|
95
|
+
limit?: number;
|
|
96
|
+
}
|
|
97
|
+
export interface ExportResult {
|
|
98
|
+
version: string;
|
|
99
|
+
exported_at: string;
|
|
100
|
+
entity_count: number;
|
|
101
|
+
entities: Array<{
|
|
102
|
+
name: string;
|
|
103
|
+
type: string;
|
|
104
|
+
namespace: string;
|
|
105
|
+
observations: string[];
|
|
106
|
+
tags: string[];
|
|
107
|
+
relations: Array<{
|
|
108
|
+
to: string;
|
|
109
|
+
type: string;
|
|
110
|
+
}>;
|
|
111
|
+
}>;
|
|
112
|
+
}
|
|
113
|
+
export interface ImportInput {
|
|
114
|
+
data: ExportResult;
|
|
115
|
+
namespace?: string;
|
|
116
|
+
merge_strategy: 'skip' | 'overwrite' | 'append';
|
|
117
|
+
}
|
|
118
|
+
export interface ImportResult {
|
|
119
|
+
imported: number;
|
|
120
|
+
skipped: number;
|
|
121
|
+
appended: number;
|
|
122
|
+
errors: string[];
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface UpdateCheck {
|
|
2
|
+
currentVersion: string;
|
|
3
|
+
latestVersion: string | null;
|
|
4
|
+
checkedAt: string;
|
|
5
|
+
updateAvailable: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function checkForUpdate(currentVersion: string): Promise<UpdateCheck>;
|
|
8
|
+
export declare function getLastUpdateCheck(): UpdateCheck | null;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=version-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/core/version-check.ts"],"names":[],"mappings":"AAOA,UAAU,WAAW;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAMD,wBAAsB,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA4BjF;AAKD,wBAAgB,kBAAkB,IAAI,WAAW,GAAG,IAAI,CAOvD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import { execFile } from 'child_process';
|
|
5
|
+
const UPDATE_CHECK_PATH = path.join(os.homedir(), '.memesh', 'update-check.json');
|
|
6
|
+
export async function checkForUpdate(currentVersion) {
|
|
7
|
+
const result = {
|
|
8
|
+
currentVersion,
|
|
9
|
+
latestVersion: null,
|
|
10
|
+
checkedAt: new Date().toISOString(),
|
|
11
|
+
updateAvailable: false,
|
|
12
|
+
};
|
|
13
|
+
try {
|
|
14
|
+
const latest = await new Promise((resolve, reject) => {
|
|
15
|
+
execFile('npm', ['show', '@pcircle/memesh', 'version'], { timeout: 5000 }, (err, stdout) => {
|
|
16
|
+
if (err)
|
|
17
|
+
reject(err);
|
|
18
|
+
else
|
|
19
|
+
resolve(stdout.trim());
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
result.latestVersion = latest;
|
|
23
|
+
result.updateAvailable = latest !== currentVersion;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
fs.mkdirSync(path.dirname(UPDATE_CHECK_PATH), { recursive: true });
|
|
29
|
+
fs.writeFileSync(UPDATE_CHECK_PATH, JSON.stringify(result, null, 2));
|
|
30
|
+
}
|
|
31
|
+
catch { }
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
export function getLastUpdateCheck() {
|
|
35
|
+
try {
|
|
36
|
+
if (!fs.existsSync(UPDATE_CHECK_PATH))
|
|
37
|
+
return null;
|
|
38
|
+
return JSON.parse(fs.readFileSync(UPDATE_CHECK_PATH, 'utf8'));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=version-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/core/version-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC;AAalF,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,cAAsB;IACzD,MAAM,MAAM,GAAgB;QAC1B,cAAc;QACd,aAAa,EAAE,IAAI;QACnB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,eAAe,EAAE,KAAK;KACvB,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3D,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,iBAAiB,EAAE,SAAS,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;gBACzF,IAAI,GAAG;oBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;oBAChB,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9B,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,aAAa,GAAG,MAAM,CAAC;QAC9B,MAAM,CAAC,eAAe,GAAG,MAAM,KAAK,cAAc,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;IAET,CAAC;IAGD,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,iBAAiB,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,EAAE,CAAC,aAAa,CAAC,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,OAAO,MAAM,CAAC;AAChB,CAAC;AAKD,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC;QACH,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC;YAAE,OAAO,IAAI,CAAC;QACnD,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
package/dist/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAkEtC,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAsD/D;AAED,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED,wBAAgB,WAAW,IAAI,QAAQ,CAAC,QAAQ,CAG/C"}
|
package/dist/db.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import Database from 'better-sqlite3';
|
|
2
|
+
import * as sqliteVec from 'sqlite-vec';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import os from 'os';
|
|
4
5
|
import fs from 'fs';
|
|
6
|
+
import { runAutoDecay } from './core/lifecycle.js';
|
|
5
7
|
let db = null;
|
|
6
8
|
const SCHEMA_SQL = `
|
|
7
9
|
CREATE TABLE IF NOT EXISTS entities (
|
|
@@ -41,6 +43,13 @@ CREATE TABLE IF NOT EXISTS tags (
|
|
|
41
43
|
|
|
42
44
|
CREATE INDEX IF NOT EXISTS idx_tags_entity ON tags(entity_id);
|
|
43
45
|
CREATE INDEX IF NOT EXISTS idx_tags_tag ON tags(tag);
|
|
46
|
+
DELETE FROM tags
|
|
47
|
+
WHERE id NOT IN (
|
|
48
|
+
SELECT MIN(id)
|
|
49
|
+
FROM tags
|
|
50
|
+
GROUP BY entity_id, tag
|
|
51
|
+
);
|
|
52
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_tags_entity_tag_unique ON tags(entity_id, tag);
|
|
44
53
|
CREATE INDEX IF NOT EXISTS idx_observations_entity ON observations(entity_id);
|
|
45
54
|
CREATE INDEX IF NOT EXISTS idx_relations_from ON relations(from_entity_id);
|
|
46
55
|
CREATE INDEX IF NOT EXISTS idx_relations_to ON relations(to_entity_id);
|
|
@@ -64,6 +73,30 @@ export function openDatabase(dbPath) {
|
|
|
64
73
|
db.pragma('foreign_keys = ON');
|
|
65
74
|
db.exec(SCHEMA_SQL);
|
|
66
75
|
db.exec(FTS_SQL);
|
|
76
|
+
const columns = db.prepare("PRAGMA table_info(entities)").all();
|
|
77
|
+
if (!columns.some((c) => c.name === 'status')) {
|
|
78
|
+
db.exec("ALTER TABLE entities ADD COLUMN status TEXT NOT NULL DEFAULT 'active'");
|
|
79
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_entities_status ON entities(status)");
|
|
80
|
+
}
|
|
81
|
+
const scoringCols = db.prepare("PRAGMA table_info(entities)").all();
|
|
82
|
+
if (!scoringCols.some((c) => c.name === 'access_count')) {
|
|
83
|
+
db.exec("ALTER TABLE entities ADD COLUMN access_count INTEGER DEFAULT 0");
|
|
84
|
+
db.exec("ALTER TABLE entities ADD COLUMN last_accessed_at TIMESTAMP");
|
|
85
|
+
db.exec("ALTER TABLE entities ADD COLUMN confidence REAL DEFAULT 1.0");
|
|
86
|
+
db.exec("ALTER TABLE entities ADD COLUMN valid_from TIMESTAMP");
|
|
87
|
+
db.exec("ALTER TABLE entities ADD COLUMN valid_until TIMESTAMP");
|
|
88
|
+
}
|
|
89
|
+
if (!scoringCols.some((c) => c.name === 'namespace')) {
|
|
90
|
+
db.exec("ALTER TABLE entities ADD COLUMN namespace TEXT DEFAULT 'personal'");
|
|
91
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_entities_namespace ON entities(namespace)");
|
|
92
|
+
}
|
|
93
|
+
runAutoDecay(db);
|
|
94
|
+
sqliteVec.load(db);
|
|
95
|
+
db.exec(`
|
|
96
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS entities_vec USING vec0(
|
|
97
|
+
embedding float[384]
|
|
98
|
+
);
|
|
99
|
+
`);
|
|
67
100
|
return db;
|
|
68
101
|
}
|
|
69
102
|
export function closeDatabase() {
|
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;AACtC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,31 +1,6 @@
|
|
|
1
1
|
import Database from 'better-sqlite3';
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
name: string;
|
|
5
|
-
type: string;
|
|
6
|
-
created_at: string;
|
|
7
|
-
metadata?: any;
|
|
8
|
-
observations: string[];
|
|
9
|
-
tags: string[];
|
|
10
|
-
relations?: Relation[];
|
|
11
|
-
}
|
|
12
|
-
export interface Relation {
|
|
13
|
-
from: string;
|
|
14
|
-
to: string;
|
|
15
|
-
type: string;
|
|
16
|
-
metadata?: any;
|
|
17
|
-
}
|
|
18
|
-
export interface CreateEntityInput {
|
|
19
|
-
name: string;
|
|
20
|
-
type: string;
|
|
21
|
-
observations?: string[];
|
|
22
|
-
tags?: string[];
|
|
23
|
-
metadata?: any;
|
|
24
|
-
}
|
|
25
|
-
export interface SearchOptions {
|
|
26
|
-
tag?: string;
|
|
27
|
-
limit?: number;
|
|
28
|
-
}
|
|
2
|
+
export type { Entity, Relation, CreateEntityInput, SearchOptions } from './core/types.js';
|
|
3
|
+
import type { Entity, Relation, CreateEntityInput, SearchOptions } from './core/types.js';
|
|
29
4
|
export declare class KnowledgeGraph {
|
|
30
5
|
private db;
|
|
31
6
|
constructor(db: Database.Database);
|
|
@@ -33,16 +8,27 @@ export declare class KnowledgeGraph {
|
|
|
33
8
|
observations?: string[];
|
|
34
9
|
tags?: string[];
|
|
35
10
|
metadata?: any;
|
|
11
|
+
namespace?: string;
|
|
36
12
|
}): number;
|
|
37
13
|
createEntitiesBatch(entities: CreateEntityInput[]): void;
|
|
38
14
|
createRelation(fromName: string, toName: string, relationType: string, metadata?: any): void;
|
|
39
15
|
getEntity(name: string): Entity | null;
|
|
40
16
|
getRelations(entityName: string): Relation[];
|
|
41
17
|
search(query?: string, opts?: SearchOptions): Entity[];
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
18
|
+
trackAccess(entityIds: number[]): void;
|
|
19
|
+
findConflicts(entityNames: string[]): string[];
|
|
20
|
+
listRecent(limit?: number, includeArchived?: boolean, namespace?: string): Entity[];
|
|
21
|
+
private listRecentByTag;
|
|
22
|
+
archiveEntity(name: string): {
|
|
23
|
+
archived: boolean;
|
|
24
|
+
name?: string;
|
|
25
|
+
previousStatus?: string;
|
|
26
|
+
};
|
|
27
|
+
removeObservation(entityName: string, observationContent: string): {
|
|
28
|
+
removed: boolean;
|
|
29
|
+
remainingObservations: number;
|
|
45
30
|
};
|
|
31
|
+
private deleteEntity;
|
|
46
32
|
private rebuildFts;
|
|
47
33
|
}
|
|
48
34
|
//# sourceMappingURL=knowledge-graph.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"knowledge-graph.d.ts","sourceRoot":"","sources":["../src/knowledge-graph.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"knowledge-graph.d.ts","sourceRoot":"","sources":["../src/knowledge-graph.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAE1F,qBAAa,cAAc;IACb,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,QAAQ,CAAC,QAAQ;IAEzC,YAAY,CACV,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,GAAG,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GACtF,MAAM;IA6DT,mBAAmB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAcxD,cAAc,CACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,QAAQ,CAAC,EAAE,GAAG,GACb,IAAI;IA2BP,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAwCtC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,QAAQ,EAAE;IAmB5C,MAAM,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,MAAM,EAAE;IAiHtD,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAkBtC,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE;IAuB9C,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE;IAmBnF,OAAO,CAAC,eAAe;IA4BvB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE;IA+B1F,iBAAiB,CACf,UAAU,EAAE,MAAM,EAClB,kBAAkB,EAAE,MAAM,GACzB;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,qBAAqB,EAAE,MAAM,CAAA;KAAE;IA8BtD,OAAO,CAAC,YAAY;IAyBpB,OAAO,CAAC,UAAU;CAsBnB"}
|
package/dist/knowledge-graph.js
CHANGED
|
@@ -5,19 +5,25 @@ export class KnowledgeGraph {
|
|
|
5
5
|
}
|
|
6
6
|
createEntity(name, type, opts) {
|
|
7
7
|
const insertResult = this.db
|
|
8
|
-
.prepare('INSERT OR IGNORE INTO entities (name, type, metadata) VALUES (?, ?, ?)')
|
|
9
|
-
.run(name, type, opts?.metadata ? JSON.stringify(opts.metadata) : null);
|
|
8
|
+
.prepare('INSERT OR IGNORE INTO entities (name, type, metadata, namespace) VALUES (?, ?, ?, ?)')
|
|
9
|
+
.run(name, type, opts?.metadata ? JSON.stringify(opts.metadata) : null, opts?.namespace ?? 'personal');
|
|
10
10
|
const isNewEntity = insertResult.changes > 0;
|
|
11
11
|
const row = this.db
|
|
12
|
-
.prepare('SELECT id FROM entities WHERE name = ?')
|
|
12
|
+
.prepare('SELECT id, status FROM entities WHERE name = ?')
|
|
13
13
|
.get(name);
|
|
14
14
|
const entityId = row.id;
|
|
15
|
-
const
|
|
15
|
+
const wasArchived = !isNewEntity && row.status === 'archived';
|
|
16
|
+
if (wasArchived) {
|
|
17
|
+
this.db
|
|
18
|
+
.prepare("UPDATE entities SET status = 'active' WHERE name = ?")
|
|
19
|
+
.run(name);
|
|
20
|
+
}
|
|
21
|
+
const prevObs = isNewEntity || wasArchived
|
|
16
22
|
? []
|
|
17
23
|
: this.db
|
|
18
24
|
.prepare('SELECT content FROM observations WHERE entity_id = ?')
|
|
19
25
|
.all(entityId);
|
|
20
|
-
const prevObsText = isNewEntity
|
|
26
|
+
const prevObsText = isNewEntity || wasArchived
|
|
21
27
|
? undefined
|
|
22
28
|
: prevObs.map((o) => o.content).join(' ');
|
|
23
29
|
if (opts?.observations?.length) {
|
|
@@ -28,7 +34,7 @@ export class KnowledgeGraph {
|
|
|
28
34
|
}
|
|
29
35
|
this.rebuildFts(entityId, name, prevObsText);
|
|
30
36
|
if (opts?.tags?.length) {
|
|
31
|
-
const insertTag = this.db.prepare('INSERT INTO tags (entity_id, tag) VALUES (?, ?)');
|
|
37
|
+
const insertTag = this.db.prepare('INSERT OR IGNORE INTO tags (entity_id, tag) VALUES (?, ?)');
|
|
32
38
|
for (const tag of opts.tags) {
|
|
33
39
|
insertTag.run(entityId, tag);
|
|
34
40
|
}
|
|
@@ -42,6 +48,7 @@ export class KnowledgeGraph {
|
|
|
42
48
|
observations: e.observations,
|
|
43
49
|
tags: e.tags,
|
|
44
50
|
metadata: e.metadata,
|
|
51
|
+
namespace: e.namespace,
|
|
45
52
|
});
|
|
46
53
|
}
|
|
47
54
|
});
|
|
@@ -66,7 +73,7 @@ export class KnowledgeGraph {
|
|
|
66
73
|
}
|
|
67
74
|
getEntity(name) {
|
|
68
75
|
const row = this.db
|
|
69
|
-
.prepare('SELECT id, name, type, created_at, metadata FROM entities WHERE name = ?')
|
|
76
|
+
.prepare('SELECT id, name, type, created_at, metadata, status, access_count, last_accessed_at, confidence, valid_from, valid_until, namespace FROM entities WHERE name = ?')
|
|
70
77
|
.get(name);
|
|
71
78
|
if (!row)
|
|
72
79
|
return null;
|
|
@@ -88,6 +95,13 @@ export class KnowledgeGraph {
|
|
|
88
95
|
observations,
|
|
89
96
|
tags,
|
|
90
97
|
relations: relations.length > 0 ? relations : undefined,
|
|
98
|
+
...(row.status === 'archived' ? { archived: true } : {}),
|
|
99
|
+
access_count: row.access_count ?? 0,
|
|
100
|
+
last_accessed_at: row.last_accessed_at ?? undefined,
|
|
101
|
+
confidence: row.confidence ?? 1.0,
|
|
102
|
+
valid_from: row.valid_from ?? undefined,
|
|
103
|
+
valid_until: row.valid_until ?? undefined,
|
|
104
|
+
namespace: row.namespace ?? 'personal',
|
|
91
105
|
};
|
|
92
106
|
}
|
|
93
107
|
getRelations(entityName) {
|
|
@@ -108,49 +122,216 @@ export class KnowledgeGraph {
|
|
|
108
122
|
search(query, opts) {
|
|
109
123
|
const limit = opts?.limit ?? 20;
|
|
110
124
|
if (!query || query.trim() === '') {
|
|
111
|
-
|
|
125
|
+
if (opts?.tag) {
|
|
126
|
+
return this.listRecentByTag(opts.tag, limit, opts?.includeArchived, opts?.namespace);
|
|
127
|
+
}
|
|
128
|
+
return this.listRecent(limit, opts?.includeArchived, opts?.namespace);
|
|
112
129
|
}
|
|
113
130
|
const sanitized = query.replace(/"/g, '""').trim();
|
|
114
131
|
const tokens = sanitized.split(/\s+/).filter((t) => t.length > 0);
|
|
115
132
|
if (tokens.length === 0)
|
|
116
|
-
return this.listRecent(limit);
|
|
133
|
+
return this.listRecent(limit, opts?.includeArchived, opts?.namespace);
|
|
117
134
|
const ftsQuery = tokens.map((token) => `"${token}"`).join(' ');
|
|
135
|
+
const statusFilter = opts?.includeArchived ? '' : "AND e.status = 'active'";
|
|
136
|
+
const namespaceFilter = opts?.namespace ? 'AND e.namespace = ?' : '';
|
|
118
137
|
let ftsRows;
|
|
119
138
|
try {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
.
|
|
139
|
+
if (opts?.tag) {
|
|
140
|
+
const params = [ftsQuery, opts.tag];
|
|
141
|
+
if (opts?.namespace)
|
|
142
|
+
params.push(opts.namespace);
|
|
143
|
+
params.push(limit);
|
|
144
|
+
ftsRows = this.db
|
|
145
|
+
.prepare(`SELECT DISTINCT e.id, e.name FROM entities_fts f
|
|
146
|
+
JOIN entities e ON e.id = f.rowid
|
|
147
|
+
JOIN tags t ON t.entity_id = e.id
|
|
148
|
+
WHERE entities_fts MATCH ?
|
|
149
|
+
AND t.tag = ?
|
|
150
|
+
${statusFilter}
|
|
151
|
+
${namespaceFilter}
|
|
152
|
+
ORDER BY e.id DESC
|
|
153
|
+
LIMIT ?`)
|
|
154
|
+
.all(...params);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
const params = [ftsQuery];
|
|
158
|
+
if (opts?.namespace)
|
|
159
|
+
params.push(opts.namespace);
|
|
160
|
+
params.push(limit);
|
|
161
|
+
ftsRows = this.db
|
|
162
|
+
.prepare(`SELECT e.id, e.name FROM entities_fts f
|
|
163
|
+
JOIN entities e ON e.id = f.rowid
|
|
164
|
+
WHERE entities_fts MATCH ?
|
|
165
|
+
${statusFilter}
|
|
166
|
+
${namespaceFilter}
|
|
167
|
+
ORDER BY e.id DESC
|
|
168
|
+
LIMIT ?`)
|
|
169
|
+
.all(...params);
|
|
170
|
+
}
|
|
126
171
|
}
|
|
127
172
|
catch (err) {
|
|
128
173
|
if (err.message?.includes('fts5'))
|
|
129
174
|
return [];
|
|
130
175
|
throw err;
|
|
131
176
|
}
|
|
132
|
-
if (ftsRows.length === 0)
|
|
133
|
-
return [];
|
|
134
177
|
const results = [];
|
|
178
|
+
const seenIds = new Set();
|
|
135
179
|
for (const ftsRow of ftsRows) {
|
|
136
180
|
const entity = this.getEntity(ftsRow.name);
|
|
137
181
|
if (!entity)
|
|
138
182
|
continue;
|
|
139
|
-
|
|
140
|
-
|
|
183
|
+
seenIds.add(ftsRow.id);
|
|
184
|
+
results.push(entity);
|
|
185
|
+
}
|
|
186
|
+
if (opts?.includeArchived) {
|
|
187
|
+
const tagJoin = opts?.tag ? 'JOIN tags t ON t.entity_id = e.id' : '';
|
|
188
|
+
const tagFilter = opts?.tag ? 'AND t.tag = ?' : '';
|
|
189
|
+
const archivedNamespaceFilter = opts?.namespace ? 'AND e.namespace = ?' : '';
|
|
190
|
+
const archivedParams = [`%${query}%`, `%${query}%`];
|
|
191
|
+
if (opts?.tag)
|
|
192
|
+
archivedParams.push(opts.tag);
|
|
193
|
+
if (opts?.namespace)
|
|
194
|
+
archivedParams.push(opts.namespace);
|
|
195
|
+
const archivedRows = this.db
|
|
196
|
+
.prepare(`SELECT DISTINCT e.id, e.name
|
|
197
|
+
FROM entities e
|
|
198
|
+
LEFT JOIN observations o ON o.entity_id = e.id
|
|
199
|
+
${tagJoin}
|
|
200
|
+
WHERE e.status = 'archived'
|
|
201
|
+
AND (e.name LIKE ? OR o.content LIKE ?)
|
|
202
|
+
${tagFilter}
|
|
203
|
+
${archivedNamespaceFilter}
|
|
204
|
+
ORDER BY e.id DESC
|
|
205
|
+
LIMIT ?`)
|
|
206
|
+
.all(...archivedParams, limit);
|
|
207
|
+
for (const row of archivedRows) {
|
|
208
|
+
if (seenIds.has(row.id))
|
|
209
|
+
continue;
|
|
210
|
+
const entity = this.getEntity(row.name);
|
|
211
|
+
if (!entity)
|
|
141
212
|
continue;
|
|
213
|
+
results.push(entity);
|
|
142
214
|
}
|
|
143
|
-
results.push(entity);
|
|
144
215
|
}
|
|
216
|
+
const entityIds = results.map((e) => e.id);
|
|
217
|
+
this.trackAccess(entityIds);
|
|
145
218
|
return results;
|
|
146
219
|
}
|
|
147
|
-
|
|
220
|
+
trackAccess(entityIds) {
|
|
221
|
+
if (entityIds.length === 0)
|
|
222
|
+
return;
|
|
223
|
+
const now = new Date().toISOString();
|
|
224
|
+
const stmt = this.db.prepare('UPDATE entities SET access_count = access_count + 1, last_accessed_at = ? WHERE id = ?');
|
|
225
|
+
const txn = this.db.transaction(() => {
|
|
226
|
+
for (const id of entityIds) {
|
|
227
|
+
stmt.run(now, id);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
txn();
|
|
231
|
+
}
|
|
232
|
+
findConflicts(entityNames) {
|
|
233
|
+
if (entityNames.length < 2)
|
|
234
|
+
return [];
|
|
235
|
+
const conflicts = [];
|
|
236
|
+
const placeholders = entityNames.map(() => '?').join(',');
|
|
237
|
+
const rows = this.db.prepare(`
|
|
238
|
+
SELECT e_from.name AS from_name, e_to.name AS to_name
|
|
239
|
+
FROM relations r
|
|
240
|
+
JOIN entities e_from ON r.from_entity_id = e_from.id
|
|
241
|
+
JOIN entities e_to ON r.to_entity_id = e_to.id
|
|
242
|
+
WHERE r.relation_type = 'contradicts'
|
|
243
|
+
AND e_from.name IN (${placeholders})
|
|
244
|
+
AND e_to.name IN (${placeholders})
|
|
245
|
+
`).all(...entityNames, ...entityNames);
|
|
246
|
+
for (const row of rows) {
|
|
247
|
+
conflicts.push(`"${row.from_name}" contradicts "${row.to_name}"`);
|
|
248
|
+
}
|
|
249
|
+
return conflicts;
|
|
250
|
+
}
|
|
251
|
+
listRecent(limit, includeArchived, namespace) {
|
|
252
|
+
const statusFilter = includeArchived ? '' : "AND status = 'active'";
|
|
253
|
+
const namespaceFilter = namespace ? 'AND namespace = ?' : '';
|
|
254
|
+
const params = [];
|
|
255
|
+
if (namespace)
|
|
256
|
+
params.push(namespace);
|
|
257
|
+
params.push(limit ?? 20);
|
|
148
258
|
const rows = this.db
|
|
149
|
-
.prepare(
|
|
150
|
-
.all(
|
|
151
|
-
|
|
259
|
+
.prepare(`SELECT name FROM entities WHERE 1=1 ${statusFilter} ${namespaceFilter} ORDER BY id DESC LIMIT ?`)
|
|
260
|
+
.all(...params);
|
|
261
|
+
const results = rows
|
|
152
262
|
.map((r) => this.getEntity(r.name))
|
|
153
263
|
.filter((e) => e !== null);
|
|
264
|
+
const entityIds = results.map((e) => e.id);
|
|
265
|
+
this.trackAccess(entityIds);
|
|
266
|
+
return results;
|
|
267
|
+
}
|
|
268
|
+
listRecentByTag(tag, limit, includeArchived, namespace) {
|
|
269
|
+
const statusFilter = includeArchived ? '' : "AND e.status = 'active'";
|
|
270
|
+
const namespaceFilter = namespace ? 'AND e.namespace = ?' : '';
|
|
271
|
+
const params = [tag];
|
|
272
|
+
if (namespace)
|
|
273
|
+
params.push(namespace);
|
|
274
|
+
params.push(limit);
|
|
275
|
+
const rows = this.db
|
|
276
|
+
.prepare(`SELECT DISTINCT e.name
|
|
277
|
+
FROM entities e
|
|
278
|
+
JOIN tags t ON t.entity_id = e.id
|
|
279
|
+
WHERE t.tag = ?
|
|
280
|
+
${statusFilter}
|
|
281
|
+
${namespaceFilter}
|
|
282
|
+
ORDER BY e.id DESC
|
|
283
|
+
LIMIT ?`)
|
|
284
|
+
.all(...params);
|
|
285
|
+
const results = rows
|
|
286
|
+
.map((r) => this.getEntity(r.name))
|
|
287
|
+
.filter((e) => e !== null);
|
|
288
|
+
const entityIds = results.map((e) => e.id);
|
|
289
|
+
this.trackAccess(entityIds);
|
|
290
|
+
return results;
|
|
291
|
+
}
|
|
292
|
+
archiveEntity(name) {
|
|
293
|
+
const row = this.db
|
|
294
|
+
.prepare('SELECT id, status FROM entities WHERE name = ?')
|
|
295
|
+
.get(name);
|
|
296
|
+
if (!row)
|
|
297
|
+
return { archived: false };
|
|
298
|
+
const allObs = this.db
|
|
299
|
+
.prepare('SELECT content FROM observations WHERE entity_id = ?')
|
|
300
|
+
.all(row.id);
|
|
301
|
+
const obsText = allObs.map((o) => o.content).join(' ');
|
|
302
|
+
try {
|
|
303
|
+
this.db
|
|
304
|
+
.prepare("INSERT INTO entities_fts (entities_fts, rowid, name, observations) VALUES('delete', ?, ?, ?)")
|
|
305
|
+
.run(row.id, name, obsText);
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
}
|
|
309
|
+
this.db
|
|
310
|
+
.prepare("UPDATE entities SET status = 'archived' WHERE id = ?")
|
|
311
|
+
.run(row.id);
|
|
312
|
+
return { archived: true, name, previousStatus: row.status };
|
|
313
|
+
}
|
|
314
|
+
removeObservation(entityName, observationContent) {
|
|
315
|
+
const row = this.db
|
|
316
|
+
.prepare('SELECT id FROM entities WHERE name = ?')
|
|
317
|
+
.get(entityName);
|
|
318
|
+
if (!row)
|
|
319
|
+
return { removed: false, remainingObservations: 0 };
|
|
320
|
+
const prevObs = this.db
|
|
321
|
+
.prepare('SELECT content FROM observations WHERE entity_id = ?')
|
|
322
|
+
.all(row.id);
|
|
323
|
+
const prevObsText = prevObs.map((o) => o.content).join(' ');
|
|
324
|
+
const deleteResult = this.db
|
|
325
|
+
.prepare('DELETE FROM observations WHERE entity_id = ? AND content = ?')
|
|
326
|
+
.run(row.id, observationContent);
|
|
327
|
+
if (deleteResult.changes === 0) {
|
|
328
|
+
return { removed: false, remainingObservations: prevObs.length };
|
|
329
|
+
}
|
|
330
|
+
this.rebuildFts(row.id, entityName, prevObsText);
|
|
331
|
+
const remaining = this.db
|
|
332
|
+
.prepare('SELECT COUNT(*) as c FROM observations WHERE entity_id = ?')
|
|
333
|
+
.get(row.id);
|
|
334
|
+
return { removed: true, remainingObservations: remaining.c };
|
|
154
335
|
}
|
|
155
336
|
deleteEntity(name) {
|
|
156
337
|
const row = this.db
|