memory-eternal 0.10.31 → 0.10.32

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.
@@ -0,0 +1,61 @@
1
+ // 「常驻实例不可替换」这个**长期状态**的记忆(issue #30 第五轮复测:A: 盘那台的稳态)。
2
+ //
3
+ // 现场(报告者实测 5 天 44 次):
4
+ // 升级 → 端口上那个常驻实例仍是上一代 → 宿主探测到"漂移" → 拉起 --replace 助手
5
+ // → 助手前置探到 lock.writable = false → **正确地拒绝**(宁可拒绝也不留孤儿)
6
+ // → 旧实例继续存活 → 下次开机再报一次…… 于是「每一步都按设计工作,合起来永远换不掉」。
7
+ //
8
+ // 所以:**环境限制要当成状态记下来**,而不是每次都当"漂移"重试一遍。记下之后:
9
+ // · 面板 / align / version-check 能显示「常驻实例不可替换(环境限制)」并给出路;
10
+ // · 宿主不再每次开机都重试注定失败的替换(首次 warn,之后降级为 boot 级别的一条已知状态)。
11
+ import fs from 'node:fs'
12
+ import path from 'node:path'
13
+ import { watchdogLockPath } from './watchdog.js'
14
+
15
+ /** 状态文件与看门狗锁同目录(同一个 DSH_HOME)。 */
16
+ export function residentStatePath(env = process.env) {
17
+ return path.join(path.dirname(watchdogLockPath(env)), 'memory-eternal-state.json')
18
+ }
19
+
20
+ /** 读状态:不存在/损坏都返回 {}(绝不影响主流程)。 */
21
+ export function readResidentState(env = process.env) {
22
+ try {
23
+ const data = JSON.parse(fs.readFileSync(residentStatePath(env), 'utf8'))
24
+ return data && typeof data === 'object' ? data : {}
25
+ } catch { return {} }
26
+ }
27
+
28
+ function writeResidentState(env, data) {
29
+ const file = residentStatePath(env)
30
+ const tmp = file + '.tmp'
31
+ fs.mkdirSync(path.dirname(file), { recursive: true })
32
+ fs.writeFileSync(tmp, JSON.stringify(data, null, 2), 'utf8')
33
+ fs.renameSync(tmp, file)
34
+ }
35
+
36
+ /**
37
+ * 记下「常驻实例不可替换(环境限制)」。
38
+ * @returns {{ok:boolean, recordedAt:number, firstTime:boolean}}
39
+ */
40
+ export function recordReplaceBlocked(env = process.env, { error = '', lockPath = '', port = 0, version = '', served = '' } = {}) {
41
+ const prev = readResidentState(env).replaceBlocked
42
+ const firstTime = !prev
43
+ const at = Date.now()
44
+ const data = { ...readResidentState(env), replaceBlocked: { at, error: String(error || '').slice(0, 300), lockPath: String(lockPath || ''), port: Number(port) || 0, version: String(version || ''), served: String(served || ''), count: (prev && Number(prev.count) || 0) + 1 } }
45
+ try { writeResidentState(env, data); return { ok: true, recordedAt: at, firstTime } } catch { return { ok: false, recordedAt: at, firstTime } }
46
+ }
47
+
48
+ /** 环境修好(锁可写了)→ 清掉这条状态。 */
49
+ export function clearReplaceBlocked(env = process.env) {
50
+ const cur = readResidentState(env)
51
+ if (!cur.replaceBlocked) return false
52
+ delete cur.replaceBlocked
53
+ try { writeResidentState(env, cur); return true } catch { return false }
54
+ }
55
+
56
+ /** 供界面/报告用:这条状态是否仍然成立(默认 7 天内算"当前有效")。 */
57
+ export function replaceBlockedInfo(env = process.env, { freshMs = 7 * 24 * 3600 * 1000 } = {}) {
58
+ const b = readResidentState(env).replaceBlocked
59
+ if (!b) return null
60
+ return { ...b, fresh: Date.now() - Number(b.at || 0) < freshMs }
61
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memory-eternal",
3
- "version": "0.10.31",
3
+ "version": "0.10.32",
4
4
  "description": "记忆核心(Memory Eternal):自研的 DeepSeek Harness 记忆插件,不移植任何既有记忆框架——对话结束后自动沉淀知识卡到本地 Markdown Vault(自研去重、自研 CJK 检索、可 git 管理),设置页提供图形化知识库(统计 / 搜索 / 知识图谱 + 侧边栏一键弹窗),Agent 通过 memory_recall 工具按需召回历史上下文。零人工干预。",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -64,7 +64,7 @@
64
64
  "prepublishOnly": "node build.mjs",
65
65
  "release": "node scripts/release.mjs",
66
66
  "release:dry": "node scripts/release.mjs --dry-run",
67
- "test": "node build.mjs && node tests/vault.test.mjs && node tests/capture.test.mjs && node tests/capture-route.test.mjs && node tests/stall.test.mjs && node tests/vault-path.test.mjs && node tests/vault-resolve.test.mjs && node tests/minhash.test.mjs && node tests/settings-save.test.mjs && node tests/config-coverage.test.mjs && node tests/config-sync.test.mjs && node tests/config-merge.test.mjs && node tests/sse.test.mjs && node tests/api.test.mjs && node tests/import-roundtrip.test.mjs && node tests/graph-perf.test.mjs && node tests/settings-compat.test.mjs && node tests/node-bin.test.mjs && node tests/watchdog-lock.test.mjs && node tests/markdown.test.mjs && node tests/feedback.test.mjs && node tests/graph-lod.test.mjs && node tests/ssr.test.mjs && node tests/web-assets.test.mjs && node tests/manifests.test.mjs && node tests/two-store.test.mjs && node tests/noise-gate.test.mjs && node tests/e2e-recall.test.mjs && node tests/issue-fixes.test.mjs && node tests/issue-fixes-2.test.mjs && node tests/issue-fixes-3.test.mjs && node tests/watchdog-orphans.test.mjs && node tests/watchdog-restart.test.mjs && node tests/readme-i18n.test.mjs && node tests/issue-fixes-4.test.mjs && node tests/host-drain.test.mjs && node tests/e2e-host-drain.mjs && node tests/issue-fixes-5.test.mjs && node tests/issue-fixes-6.test.mjs && node tests/capture-json-repair.test.mjs && node tests/csrf-origin.test.mjs && node tests/watchdog-orphan-web.test.mjs && node tests/config-validate.test.mjs && node tests/issue-fixes-8.test.mjs && node tests/issue-fixes-9.test.mjs && node tests/release-verify.test.mjs && node tests/refine.test.mjs && node tests/db-restore.test.mjs && node tests/align.test.mjs && node tests/tags-normalize.test.mjs"
67
+ "test": "node build.mjs && node tests/vault.test.mjs && node tests/capture.test.mjs && node tests/capture-route.test.mjs && node tests/stall.test.mjs && node tests/vault-path.test.mjs && node tests/vault-resolve.test.mjs && node tests/minhash.test.mjs && node tests/settings-save.test.mjs && node tests/config-coverage.test.mjs && node tests/config-sync.test.mjs && node tests/config-merge.test.mjs && node tests/sse.test.mjs && node tests/api.test.mjs && node tests/import-roundtrip.test.mjs && node tests/graph-perf.test.mjs && node tests/settings-compat.test.mjs && node tests/node-bin.test.mjs && node tests/watchdog-lock.test.mjs && node tests/markdown.test.mjs && node tests/feedback.test.mjs && node tests/graph-lod.test.mjs && node tests/ssr.test.mjs && node tests/web-assets.test.mjs && node tests/manifests.test.mjs && node tests/two-store.test.mjs && node tests/noise-gate.test.mjs && node tests/e2e-recall.test.mjs && node tests/issue-fixes.test.mjs && node tests/issue-fixes-2.test.mjs && node tests/issue-fixes-3.test.mjs && node tests/watchdog-orphans.test.mjs && node tests/watchdog-restart.test.mjs && node tests/readme-i18n.test.mjs && node tests/issue-fixes-4.test.mjs && node tests/host-drain.test.mjs && node tests/e2e-host-drain.mjs && node tests/issue-fixes-5.test.mjs && node tests/issue-fixes-6.test.mjs && node tests/capture-json-repair.test.mjs && node tests/csrf-origin.test.mjs && node tests/watchdog-orphan-web.test.mjs && node tests/config-validate.test.mjs && node tests/issue-fixes-8.test.mjs && node tests/issue-fixes-9.test.mjs && node tests/release-verify.test.mjs && node tests/refine.test.mjs && node tests/db-restore.test.mjs && node tests/align.test.mjs && node tests/tags-normalize.test.mjs && node tests/resident-state.test.mjs"
68
68
  },
69
69
  "dependencies": {
70
70
  "@deepseek-ai/schemastery": "^3.18.1"