sigma-memory 0.1.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/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +182 -0
- package/dist/index.js.map +1 -0
- package/dist/notes.d.ts +40 -0
- package/dist/notes.d.ts.map +1 -0
- package/dist/notes.js +147 -0
- package/dist/notes.js.map +1 -0
- package/dist/ontology.d.ts +65 -0
- package/dist/ontology.d.ts.map +1 -0
- package/dist/ontology.js +280 -0
- package/dist/ontology.js.map +1 -0
- package/dist/qmd.d.ts +35 -0
- package/dist/qmd.d.ts.map +1 -0
- package/dist/qmd.js +162 -0
- package/dist/qmd.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +24 -0
- package/src/index.ts +178 -0
- package/src/notes.ts +163 -0
- package/src/ontology.ts +348 -0
- package/src/qmd.ts +180 -0
- package/src/types.ts +96 -0
package/src/qmd.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import type { MemoryConfig, SearchResult } from './types.js';
|
|
3
|
+
|
|
4
|
+
export class QMDManager {
|
|
5
|
+
private config: MemoryConfig;
|
|
6
|
+
private qmdCommand: string;
|
|
7
|
+
|
|
8
|
+
constructor(config: MemoryConfig) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
this.qmdCommand = config.qmdCommand || 'qmd';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Retourne true si QMD est installé et fonctionnel
|
|
15
|
+
*/
|
|
16
|
+
isAvailable(): boolean {
|
|
17
|
+
if (!this.config.qmdEnabled) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
// Teste si le binaire QMD est accessible
|
|
23
|
+
execSync(`${this.qmdCommand} --version`, {
|
|
24
|
+
stdio: 'ignore',
|
|
25
|
+
timeout: 5000
|
|
26
|
+
});
|
|
27
|
+
return true;
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Lance `qmd query` et parse les résultats
|
|
35
|
+
*/
|
|
36
|
+
async search(query: string, maxResults = 10): Promise<SearchResult[]> {
|
|
37
|
+
if (!this.isAvailable()) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const output = execSync(
|
|
43
|
+
`${this.qmdCommand} query "${query.replace(/"/g, '\\"')}" --limit ${maxResults} --format json`,
|
|
44
|
+
{
|
|
45
|
+
encoding: 'utf8',
|
|
46
|
+
timeout: 30000,
|
|
47
|
+
cwd: this.config.memoryDir
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
if (!output.trim()) {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const result = JSON.parse(output);
|
|
56
|
+
|
|
57
|
+
// Le format attendu est { results: [{file, line, content, score}] }
|
|
58
|
+
if (result.results && Array.isArray(result.results)) {
|
|
59
|
+
return result.results.map((item: any) => ({
|
|
60
|
+
file: item.file || '',
|
|
61
|
+
line: item.line || 0,
|
|
62
|
+
content: item.content || '',
|
|
63
|
+
score: item.score || 0
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return [];
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('QMD search error:', error);
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Lance `qmd update` pour reindexer
|
|
76
|
+
*/
|
|
77
|
+
async update(): Promise<boolean> {
|
|
78
|
+
if (!this.isAvailable()) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
execSync(`${this.qmdCommand} update`, {
|
|
84
|
+
stdio: 'ignore',
|
|
85
|
+
timeout: 60000,
|
|
86
|
+
cwd: this.config.memoryDir
|
|
87
|
+
});
|
|
88
|
+
return true;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error('QMD update error:', error);
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Lance `qmd embed` pour recalculer les embeddings
|
|
97
|
+
*/
|
|
98
|
+
async embed(): Promise<boolean> {
|
|
99
|
+
if (!this.isAvailable()) {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
execSync(`${this.qmdCommand} embed`, {
|
|
105
|
+
stdio: 'ignore',
|
|
106
|
+
timeout: 300000, // 5 minutes pour les embeddings
|
|
107
|
+
cwd: this.config.memoryDir
|
|
108
|
+
});
|
|
109
|
+
return true;
|
|
110
|
+
} catch (error) {
|
|
111
|
+
console.error('QMD embed error:', error);
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Liste les collections QMD
|
|
118
|
+
*/
|
|
119
|
+
async collections(): Promise<string[]> {
|
|
120
|
+
if (!this.isAvailable()) {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const output = execSync(`${this.qmdCommand} collections --format json`, {
|
|
126
|
+
encoding: 'utf8',
|
|
127
|
+
timeout: 10000,
|
|
128
|
+
cwd: this.config.memoryDir
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
if (!output.trim()) {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const result = JSON.parse(output);
|
|
136
|
+
|
|
137
|
+
// Retourne la liste des noms de collections
|
|
138
|
+
if (result.collections && Array.isArray(result.collections)) {
|
|
139
|
+
return result.collections.map((col: any) => col.name || col);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return [];
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error('QMD collections error:', error);
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Retourne le statut (nb fichiers, nb chunks, dernière mise à jour)
|
|
151
|
+
*/
|
|
152
|
+
async status(): Promise<{ files: number; chunks: number; lastUpdate: string | null } | null> {
|
|
153
|
+
if (!this.isAvailable()) {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const output = execSync(`${this.qmdCommand} status --format json`, {
|
|
159
|
+
encoding: 'utf8',
|
|
160
|
+
timeout: 10000,
|
|
161
|
+
cwd: this.config.memoryDir
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (!output.trim()) {
|
|
165
|
+
return { files: 0, chunks: 0, lastUpdate: null };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const result = JSON.parse(output);
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
files: result.files || 0,
|
|
172
|
+
chunks: result.chunks || 0,
|
|
173
|
+
lastUpdate: result.lastUpdate || null
|
|
174
|
+
};
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error('QMD status error:', error);
|
|
177
|
+
return { files: 0, chunks: 0, lastUpdate: null };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export interface MemoryConfig {
|
|
2
|
+
memoryDir: string; // ~/.phi/memory/
|
|
3
|
+
projectMemoryDir: string; // .phi/memory/ (dans le projet courant)
|
|
4
|
+
ontologyPath: string; // ~/.phi/memory/ontology/graph.jsonl
|
|
5
|
+
qmdEnabled: boolean;
|
|
6
|
+
qmdCommand?: string; // Chemin vers le binaire QMD
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface SearchResult {
|
|
10
|
+
file: string;
|
|
11
|
+
line: number;
|
|
12
|
+
content: string;
|
|
13
|
+
score: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface OntologyEntity {
|
|
17
|
+
id: string;
|
|
18
|
+
type: 'Person' | 'Project' | 'Device' | 'Account' | 'Document' | 'Service' | 'Concept';
|
|
19
|
+
name: string;
|
|
20
|
+
properties: Record<string, string>;
|
|
21
|
+
createdAt: string;
|
|
22
|
+
updatedAt: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface OntologyRelation {
|
|
26
|
+
id: string;
|
|
27
|
+
from: string; // entity ID
|
|
28
|
+
to: string; // entity ID
|
|
29
|
+
type: string; // 'owns' | 'uses' | 'deploys' | 'manages' | 'depends_on' | etc.
|
|
30
|
+
properties: Record<string, string>;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface Note {
|
|
35
|
+
file: string;
|
|
36
|
+
date: string;
|
|
37
|
+
content: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface UnifiedSearchResult {
|
|
41
|
+
source: 'notes' | 'ontology' | 'qmd';
|
|
42
|
+
type?: 'entity' | 'relation' | 'note' | 'file';
|
|
43
|
+
score: number;
|
|
44
|
+
data: any;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface MemoryStatus {
|
|
48
|
+
notes: {
|
|
49
|
+
count: number;
|
|
50
|
+
totalSize: number;
|
|
51
|
+
lastModified: string | null;
|
|
52
|
+
};
|
|
53
|
+
ontology: {
|
|
54
|
+
entities: number;
|
|
55
|
+
relations: number;
|
|
56
|
+
entitiesByType: Record<string, number>;
|
|
57
|
+
relationsByType: Record<string, number>;
|
|
58
|
+
};
|
|
59
|
+
qmd: {
|
|
60
|
+
available: boolean;
|
|
61
|
+
status?: {
|
|
62
|
+
files: number;
|
|
63
|
+
chunks: number;
|
|
64
|
+
lastUpdate: string | null;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Types pour les entrées JSONL de l'ontologie
|
|
70
|
+
export interface OntologyEntityEntry {
|
|
71
|
+
kind: 'entity';
|
|
72
|
+
id: string;
|
|
73
|
+
type: 'Person' | 'Project' | 'Device' | 'Account' | 'Document' | 'Service' | 'Concept';
|
|
74
|
+
name: string;
|
|
75
|
+
properties: Record<string, string>;
|
|
76
|
+
createdAt: string;
|
|
77
|
+
updatedAt: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface OntologyRelationEntry {
|
|
81
|
+
kind: 'relation';
|
|
82
|
+
id: string;
|
|
83
|
+
from: string;
|
|
84
|
+
to: string;
|
|
85
|
+
type: string;
|
|
86
|
+
properties: Record<string, string>;
|
|
87
|
+
createdAt: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface OntologyDeleteEntry {
|
|
91
|
+
kind: 'delete';
|
|
92
|
+
targetId: string;
|
|
93
|
+
deletedAt: string;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export type OntologyJSONLEntry = OntologyEntityEntry | OntologyRelationEntry | OntologyDeleteEntry;
|