memory-eternal 0.3.1 → 0.3.3

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/lib/db.js CHANGED
@@ -176,3 +176,31 @@ export function closeDb(root) {
176
176
  const db = instances.get(resolved)
177
177
  if (db) { db.close(); instances.delete(resolved) }
178
178
  }
179
+
180
+ /**
181
+ * SQLite 备份:用 VACUUM INTO 创建紧凑副本。
182
+ * 保留最近 maxKeep 个备份,自动清理旧的。
183
+ */
184
+ export async function backupDb(root, { maxKeep = 7 } = {}) {
185
+ const resolved = path.resolve(root)
186
+ const dbPath = path.join(resolved, DB_FILE)
187
+ const backupDir = path.join(resolved, 'backups')
188
+ await fs.mkdir(backupDir, { recursive: true })
189
+ const now = new Date()
190
+ const date = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
191
+ const time = `${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}`
192
+ const backupPath = path.join(backupDir, `memory-eternal-${date}_${time}.db`)
193
+ try {
194
+ const db = getDb(root)
195
+ db.exec(`VACUUM INTO '${backupPath.replace(/'/g, "''")}'`)
196
+ // 清理旧备份:保留最近 maxKeep 个
197
+ const files = await fs.readdir(backupDir)
198
+ const dbBackups = files.filter(f => f.startsWith('memory-eternal-') && f.endsWith('.db')).sort().reverse()
199
+ for (const old of dbBackups.slice(maxKeep)) {
200
+ try { await fs.unlink(path.join(backupDir, old)) } catch {}
201
+ }
202
+ return { ok: true, path: backupPath, kept: Math.min(dbBackups.length, maxKeep) }
203
+ } catch (e) {
204
+ return { ok: false, error: String(e.message || e) }
205
+ }
206
+ }
package/lib/vault.js CHANGED
@@ -447,10 +447,17 @@ export async function exportCards(root) {
447
447
  /** 图谱:节点 = 卡片;边 = [[wikilink]] 或共享标签。 */
448
448
  export async function graph(root) {
449
449
  const db = getDb(root)
450
- const rows = db.prepare("SELECT * FROM cards WHERE status = 'approved' ORDER BY updated_at DESC").all()
451
- const cards = rows.map(rowToCard)
450
+ // 只选图谱需要的列,不读 body(大幅减少内存和传输量)
451
+ const rows = db.prepare("SELECT id, path, kind, title, tags, summary, status, updated_at FROM cards WHERE status = 'approved' ORDER BY updated_at DESC").all()
452
+ // body 单独按需读取(只在需要 wikilink 匹配时)
453
+ const bodyRows = db.prepare("SELECT path, body FROM cards WHERE status = 'approved'").all()
454
+ const bodyMap = new Map(bodyRows.map((r) => [r.path, r.body]))
455
+ const cards = rows.map((r) => ({
456
+ path: r.path, kind: r.kind, title: r.title, tags: JSON.parse(r.tags || '[]'),
457
+ summary: r.summary || '', updated: r.updated_at, mtime: new Date(r.updated_at).getTime(), status: r.status,
458
+ }))
459
+
452
460
  const byPath = new Map(cards.map((c) => [c.path, c]))
453
- const bodyMap = new Map(rows.map((r) => [r.path, r.body]))
454
461
 
455
462
  const nodes = cards.map((c) => ({
456
463
  id: c.path,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "记忆核心(Memory Eternal):自研的 DeepSeek Harness 记忆插件,不移植任何既有记忆框架——对话结束后自动沉淀知识卡到本地 Markdown Vault(自研去重、自研 CJK 检索、可 git 管理),设置页提供图形化知识库(统计 / 搜索 / 知识图谱 + 侧边栏一键弹窗),Agent 通过 memory_recall 工具按需召回历史上下文。零人工干预。",
5
5
  "license": "MIT",
6
6
  "repository": {