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/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;