memorix 1.9.0 → 1.9.1

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +5 -1
  3. package/README.zh-CN.md +1 -1
  4. package/dist/cli/index.js +2508 -1843
  5. package/dist/index.js +2387 -1722
  6. package/dist/maintenance-runner.js +1686 -1031
  7. package/dist/media-audio-runner.js +2185 -1530
  8. package/dist/media-video-runner.js +2185 -1530
  9. package/dist/memcode-runtime/CHANGELOG.md +28 -0
  10. package/dist/sdk.js +2449 -1720
  11. package/dist/vector-backfill-runner.js +2183 -1528
  12. package/docs/CONFIGURATION.md +22 -0
  13. package/docs/DEVELOPMENT.md +2 -2
  14. package/docs/PERFORMANCE.md +77 -20
  15. package/docs/README.md +1 -1
  16. package/package.json +2 -1
  17. package/plugins/antigravity/memorix/plugin.json +1 -1
  18. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  19. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  20. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  21. package/plugins/copilot/memorix/plugin.json +1 -1
  22. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  23. package/plugins/hermes/memorix/plugin.yaml +1 -1
  24. package/plugins/omp/memorix/package.json +1 -1
  25. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  26. package/plugins/pi/memorix/package.json +1 -1
  27. package/server.json +2 -2
  28. package/src/compact/engine.ts +14 -4
  29. package/src/memory/freshness.ts +7 -4
  30. package/src/memory/observations.ts +118 -6
  31. package/src/runtime/vector-backfill-runner.ts +1 -1
  32. package/src/sdk.ts +13 -6
  33. package/src/search/semantic-index.ts +340 -0
  34. package/src/server.ts +1 -1
  35. package/src/store/obs-store.ts +54 -2
  36. package/src/store/orama-store.ts +300 -12
  37. package/src/store/sqlite-db.ts +6 -0
  38. package/src/store/sqlite-fts.ts +164 -0
  39. package/src/store/sqlite-store.ts +83 -6
@@ -18,6 +18,13 @@
18
18
  import type { Observation } from '../types.js';
19
19
  import type { ObservationStore, StoreTransaction } from './obs-store.js';
20
20
  import { getDatabase, closeDatabase } from './sqlite-db.js';
21
+ import {
22
+ isObservationLexicalIndexEnabled,
23
+ rebuildObservationLexicalIndex,
24
+ searchObservationLexically,
25
+ type SqliteLexicalSearchOptions,
26
+ } from './sqlite-fts.js';
27
+ import type { LexicalSearchHit } from './obs-store.js';
21
28
  import path from 'node:path';
22
29
  import fs from 'node:fs';
23
30
 
@@ -126,6 +133,9 @@ export class SqliteBackend implements ObservationStore {
126
133
  private stmtSelectByProjectStatusNewest: any = null;
127
134
  private stmtCountByProject: any = null;
128
135
  private stmtCountByProjectStatus: any = null;
136
+ private stmtCountByProjectVisible: any = null;
137
+ private stmtCountByProjectStatusVisible: any = null;
138
+ private stmtCountAll: any = null;
129
139
  private stmtSelectByTopicKey: any = null;
130
140
  private stmtSelectGeneration: any = null;
131
141
  private stmtBumpGeneration: any = null;
@@ -140,7 +150,7 @@ export class SqliteBackend implements ObservationStore {
140
150
 
141
151
  // Prepare statements
142
152
  this.stmtInsert = this.db.prepare(`
143
- INSERT OR REPLACE INTO observations
153
+ INSERT INTO observations
144
154
  (id, entityName, type, title, narrative, facts, filesModified, concepts, tokens,
145
155
  createdAt, updatedAt, projectId, hasCausalLanguage, topicKey, revisionCount,
146
156
  sessionId, status, progress, source, commitHash, relatedCommits, relatedEntities,
@@ -152,8 +162,39 @@ export class SqliteBackend implements ObservationStore {
152
162
  @sessionId, @status, @progress, @source, @commitHash, @relatedCommits, @relatedEntities,
153
163
  @attachments, @sourceDetail, @valueCategory, @admissionState, @admissionReason, @visibility, @sharedWithAgentIds,
154
164
  @createdByAgentId, @writeGeneration)
165
+ ON CONFLICT(id) DO UPDATE SET
166
+ entityName = excluded.entityName,
167
+ type = excluded.type,
168
+ title = excluded.title,
169
+ narrative = excluded.narrative,
170
+ facts = excluded.facts,
171
+ filesModified = excluded.filesModified,
172
+ concepts = excluded.concepts,
173
+ tokens = excluded.tokens,
174
+ createdAt = excluded.createdAt,
175
+ updatedAt = excluded.updatedAt,
176
+ projectId = excluded.projectId,
177
+ hasCausalLanguage = excluded.hasCausalLanguage,
178
+ topicKey = excluded.topicKey,
179
+ revisionCount = excluded.revisionCount,
180
+ sessionId = excluded.sessionId,
181
+ status = excluded.status,
182
+ progress = excluded.progress,
183
+ source = excluded.source,
184
+ commitHash = excluded.commitHash,
185
+ relatedCommits = excluded.relatedCommits,
186
+ relatedEntities = excluded.relatedEntities,
187
+ attachments = excluded.attachments,
188
+ sourceDetail = excluded.sourceDetail,
189
+ valueCategory = excluded.valueCategory,
190
+ admissionState = excluded.admissionState,
191
+ admissionReason = excluded.admissionReason,
192
+ visibility = excluded.visibility,
193
+ sharedWithAgentIds = excluded.sharedWithAgentIds,
194
+ createdByAgentId = excluded.createdByAgentId,
195
+ writeGeneration = excluded.writeGeneration
155
196
  `);
156
- this.stmtUpdate = this.stmtInsert; // INSERT OR REPLACE works for both
197
+ this.stmtUpdate = this.stmtInsert;
157
198
  this.stmtSetStatus = this.db.prepare(`UPDATE observations SET status = ? WHERE id = ?`);
158
199
  this.stmtSetStatusIfCurrent = this.db.prepare(
159
200
  `UPDATE observations SET status = ? WHERE id = ? AND status = ?`,
@@ -191,6 +232,13 @@ export class SqliteBackend implements ObservationStore {
191
232
  this.stmtCountByProjectStatus = this.db.prepare(
192
233
  `SELECT COUNT(*) AS count FROM observations WHERE projectId = ? AND status = ?`,
193
234
  );
235
+ this.stmtCountByProjectVisible = this.db.prepare(
236
+ `SELECT COUNT(*) AS count FROM observations WHERE projectId = ? AND (visibility IS NULL OR visibility = 'project')`,
237
+ );
238
+ this.stmtCountByProjectStatusVisible = this.db.prepare(
239
+ `SELECT COUNT(*) AS count FROM observations WHERE projectId = ? AND status = ? AND (visibility IS NULL OR visibility = 'project')`,
240
+ );
241
+ this.stmtCountAll = this.db.prepare(`SELECT COUNT(*) AS count FROM observations`);
194
242
  this.stmtSelectByTopicKey = this.db.prepare(
195
243
  `SELECT * FROM observations WHERE projectId = ? AND topicKey = ? ORDER BY id ASC LIMIT 1`,
196
244
  );
@@ -322,10 +370,14 @@ export class SqliteBackend implements ObservationStore {
322
370
  return this.rawGetById(id);
323
371
  }
324
372
 
325
- async countByProject(projectId: string, options: { status?: string } = {}): Promise<number> {
326
- const row = options.status
327
- ? this.stmtCountByProjectStatus.get(projectId, options.status)
328
- : this.stmtCountByProject.get(projectId);
373
+ async countByProject(projectId: string, options: { status?: string; visibility?: 'project' } = {}): Promise<number> {
374
+ const row = options.visibility === 'project'
375
+ ? (options.status
376
+ ? this.stmtCountByProjectStatusVisible.get(projectId, options.status)
377
+ : this.stmtCountByProjectVisible.get(projectId))
378
+ : options.status
379
+ ? this.stmtCountByProjectStatus.get(projectId, options.status)
380
+ : this.stmtCountByProject.get(projectId);
329
381
  return Number(row?.count ?? 0);
330
382
  }
331
383
 
@@ -333,6 +385,31 @@ export class SqliteBackend implements ObservationStore {
333
385
  return this.rawLoadIdCounter();
334
386
  }
335
387
 
388
+ async countAll(): Promise<number> {
389
+ return Number(this.stmtCountAll.get()?.count ?? 0);
390
+ }
391
+
392
+ async listProjectIds(): Promise<string[]> {
393
+ return (this.db.prepare('SELECT DISTINCT projectId FROM observations ORDER BY projectId').all() as Array<{ projectId?: string }>)
394
+ .map((row) => row.projectId)
395
+ .filter((projectId): projectId is string => Boolean(projectId));
396
+ }
397
+
398
+ async searchLexical(options: SqliteLexicalSearchOptions): Promise<LexicalSearchHit[]> {
399
+ return searchObservationLexically(this.db, options).map((hit) => ({
400
+ observation: rowToObs(hit.row),
401
+ score: hit.score,
402
+ }));
403
+ }
404
+
405
+ hasLexicalIndex(): boolean {
406
+ return isObservationLexicalIndexEnabled(this.db);
407
+ }
408
+
409
+ async rebuildLexicalIndex(): Promise<boolean> {
410
+ return rebuildObservationLexicalIndex(this.db);
411
+ }
412
+
336
413
  // ── Public write (each bumps generation) ─────────────────────────
337
414
 
338
415
  async insert(obs: Observation): Promise<void> {