dsh-memory-eternal 0.7.0-rc.8 → 0.7.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/.claude-plugin/plugin.json +12 -1
- package/.codex-plugin/plugin.json +12 -1
- package/.cursor-plugin/plugin.json +12 -1
- package/README.en.md +17 -4
- package/README.md +17 -4
- package/index.js +13 -2
- package/lib/api.js +6 -3
- package/lib/capture-run.js +21 -6
- package/lib/client.js +5 -5
- package/lib/setup.js +3 -3
- package/lib/vault.js +59 -40
- package/lib/web.js +3 -2
- package/package.json +1 -1
- package/web/app.js +9 -9
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
3
|
"name": "dsh-memory-eternal",
|
|
4
|
-
"version": "0.7.0
|
|
4
|
+
"version": "0.7.0",
|
|
5
5
|
"description": "璁板繂鏍稿績锛圡emory Eternal锛夛細鐭ヨ瘑鍗¤嚜鍔ㄦ矇娣€/鍙洖锛岀粺涓€ ~/.dsh/memory-vault锛屼細璇濈粨鏉熻嚜鍔ㄥ叆搴撹繘寰呭鏍搞€?,
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "EternalNight996",
|
|
@@ -21,3 +21,14 @@
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-memory-eternal",
|
|
3
|
-
"version": "0.7.0
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "璁板繂鏍稿績锛圡emory Eternal锛夛細鐭ヨ瘑鍗¤嚜鍔ㄦ矇娣€/鍙洖锛岀粺涓€ ~/.dsh/memory-vault锛屼細璇濈粨鏉熻嚜鍔ㄥ叆搴撹繘寰呭鏍搞€?,
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "EternalNight996",
|
|
@@ -16,3 +16,14 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-memory-eternal",
|
|
3
|
-
"version": "0.7.0
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "璁板繂鏍稿績锛圡emory Eternal锛夛細鐭ヨ瘑鍗¤嚜鍔ㄦ矇娣€/鍙洖锛岀粺涓€ ~/.dsh/memory-vault锛屼細璇濈粨鏉熻嚜鍔ㄥ叆搴撹繘寰呭鏍搞€?,
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "EternalNight996",
|
|
@@ -15,3 +15,14 @@
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
package/README.en.md
CHANGED
|
@@ -41,9 +41,9 @@ After **restarting dsh web**, three things are live immediately:
|
|
|
41
41
|
| `memory_recall` tool | Agent calls it automatically when it needs history |
|
|
42
42
|
| Visual UI | Sidebar bottom `Memory` button / Settings → Memory |
|
|
43
43
|
|
|
44
|
-
**The sidebar
|
|
44
|
+
**Entry**: The sidebar-footer `Memory` button opens the vault (its left rail includes Cards / Graph / Usage / **Audit Center** / Recycle Bin / **Memory Config**); "DSH Settings → Memory" is the pure config page.
|
|
45
45
|
|
|
46
|
-
**Edit config**:
|
|
46
|
+
**Edit config**: Vault left rail "Memory Config" (or DSH Settings → Memory) → DSH memory config / cost control / auto-audit config / self-hosting — just hit "Save Config". `autoWebMode` / `watchdogAutoSpawn` changes require a DSH restart.
|
|
47
47
|
|
|
48
48
|
### 🟨 Claude Code
|
|
49
49
|
|
|
@@ -98,7 +98,7 @@ Three concepts, don't mix them:
|
|
|
98
98
|
- **Watchdog process** (`watchdogAutoSpawn`, default on) → a **standalone** node process that can pull web up even after DSH exits (~+47 MB RAM). Only turn on for 7×24 keep-alive.
|
|
99
99
|
- **Auto-mount MCP** (`autoMcpSetup`, default off) → whether to auto-write MCP into Claude Code/Codex/Cursor config. Off = don't touch your machine config; run `dsh-memory setup` manually when needed.
|
|
100
100
|
|
|
101
|
-
**Change these**:
|
|
101
|
+
**Change these**: Vault left rail "Memory Config" (or DSH Settings → Memory) → edit the table and save; `autoWebMode` / `watchdogAutoSpawn` need a DSH restart.
|
|
102
102
|
|
|
103
103
|
**MCP is a protocol, not a resident service**: the agent spawns it per session and exits when done — no "auto-start on boot" concept.
|
|
104
104
|
|
|
@@ -114,7 +114,7 @@ Three concepts, don't mix them:
|
|
|
114
114
|
|
|
115
115
|
## ⚙️ Memory Config (plain words)
|
|
116
116
|
|
|
117
|
-
> All settings live in the **left
|
|
117
|
+
> All settings live in the **vault left rail "Memory Config"** (or DSH Settings → Memory) — edit and hit "Save". Here's the full page (plugin info / Agent MCP mount status / auto-audit config):
|
|
118
118
|
|
|
119
119
|
<p align="center">
|
|
120
120
|
<img src="https://raw.githubusercontent.com/EternalNight996/dsh-memory-eternal/main/assets/screen/memory-config.png" width="880" alt="Memory config page" />
|
|
@@ -161,6 +161,19 @@ Top of the config page: **🟢 A Light / 💰 B Budget / ⭐ C Premium** — cli
|
|
|
161
161
|
|
|
162
162
|
---
|
|
163
163
|
|
|
164
|
+
## 🛡️ Audit Center & Recycle Bin
|
|
165
|
+
|
|
166
|
+
New cards go to the **Audit Center** (`pending`) by default and enter the main vault only after you approve them; rejected ones move to "Rejected", where you can restore or delete to the recycle bin. Cards matching an exemption (audit mode = skip all / exempt agents / exempt kinds) go straight in; recycle-bin cards are recoverable within 30 days, then auto-purged.
|
|
167
|
+
|
|
168
|
+
<p align="center">
|
|
169
|
+
<img src="https://raw.githubusercontent.com/EternalNight996/dsh-memory-eternal/main/assets/screen/audit-center.png" width="880" alt="Audit Center" />
|
|
170
|
+
</p>
|
|
171
|
+
|
|
172
|
+
- **Pending / Rejected** tabs, filtered by type / date / agent; select all and approve / reject / delete-to-recycle in one click.
|
|
173
|
+
- Rules in "Memory Config → Auto-audit config": `audit mode` (audit all / skip all) + `exempt agents` + `exempt kinds` + `recycle retention days`.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
164
177
|
## 🧬 Why Fully Self-built
|
|
165
178
|
|
|
166
179
|
Most memory solutions lean on third-party frameworks / spin up an MCP service / lock memory in a private store. This plugin builds the skeleton itself — **zero third-party runtime deps**, logic readable line by line:
|
package/README.md
CHANGED
|
@@ -41,9 +41,9 @@ cd ~/.dsh/profiles/web && pnpm add dsh-memory-eternal@latest
|
|
|
41
41
|
| `memory_recall` 工具 | Agent 需要历史时自动调用 |
|
|
42
42
|
| 图形化界面 | 侧边栏底部「记忆」按钮 / 设置 → 记忆 |
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
**入口**:侧边栏底部「记忆」按钮 → 记忆库(左栏含 知识卡 / 知识图谱 / 用量 / **审核中心** / 回收中心 / **记忆配置**);「DSH 设置 → 记忆」= 纯配置页。
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
**改配置**:记忆库左栏「记忆配置」(或 DSH 设置 → 记忆)→ DSH 记忆配置 / 成本控制 / 自动审核配置 / 服务自管理,点「保存配置」即写入。`autoWebMode`/`watchdogAutoSpawn` 的改动需重启 DSH 生效。
|
|
47
47
|
|
|
48
48
|
### 🟨 Claude Code
|
|
49
49
|
|
|
@@ -110,7 +110,7 @@ dsh-memory watchdog [--port 7799] # 看门狗保活 web(独立进程)
|
|
|
110
110
|
- **看门狗进程**(`watchdogAutoSpawn`,默认开)→ 一个**独立** node 进程,DSH 退出了它也能拉起 web(约 +47 MB 内存)。只在要 7×24 保活时开。
|
|
111
111
|
- **自动挂载 MCP**(`autoMcpSetup`,默认关)→ 是否自动把 MCP 写进 Claude Code/Codex/Cursor 配置。关 = 不碰你本机配置文件,需要时手动 `dsh-memory setup`。
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
**改这些**:记忆库左栏「记忆配置」(或 DSH 设置 → 记忆)→ 表格里改,点「保存配置」;`autoWebMode`/`watchdogAutoSpawn` 需重启 DSH 生效。
|
|
114
114
|
|
|
115
115
|
**MCP 是协议不是常驻服务**:agent 开会话才 spawn,用完即退,没有「开机自启」一说。
|
|
116
116
|
|
|
@@ -126,7 +126,7 @@ dsh-memory watchdog [--port 7799] # 看门狗保活 web(独立进程)
|
|
|
126
126
|
|
|
127
127
|
## ⚙️ 记忆配置(大白话)
|
|
128
128
|
|
|
129
|
-
> 所有配置都在
|
|
129
|
+
> 所有配置都在 **记忆库左栏「记忆配置」**(或 DSH 设置 → 记忆)里改,点「保存配置」生效。下图就是配置页全貌(含插件信息 / Agent MCP 挂载状态 / 自动审核配置):
|
|
130
130
|
|
|
131
131
|
<p align="center">
|
|
132
132
|
<img src="https://raw.githubusercontent.com/EternalNight996/dsh-memory-eternal/main/assets/screen/memory-config.png" width="880" alt="记忆配置页" />
|
|
@@ -173,6 +173,19 @@ dsh-memory watchdog [--port 7799] # 看门狗保活 web(独立进程)
|
|
|
173
173
|
|
|
174
174
|
---
|
|
175
175
|
|
|
176
|
+
## 🛡️ 审核中心 & 回收中心
|
|
177
|
+
|
|
178
|
+
新卡默认进**审核中心**(`pending`),由你确认后才入主库;驳回的进「已驳回」,可恢复或删除进回收站。命中免审条件(审核模式=全部免审 / 免审智能体 / 免审类型)的新卡直接入库;回收站软删卡 30 天内可恢复,超期自动永久删除。
|
|
179
|
+
|
|
180
|
+
<p align="center">
|
|
181
|
+
<img src="https://raw.githubusercontent.com/EternalNight996/dsh-memory-eternal/main/assets/screen/audit-center.png" width="880" alt="审核中心" />
|
|
182
|
+
</p>
|
|
183
|
+
|
|
184
|
+
- **待审核 / 已驳回** 双页签,按类型 / 日期 / 智能体筛选,全选后一键「批准 / 驳回 / 删除进回收站」。
|
|
185
|
+
- 审核规则在「记忆配置 → 自动审核配置」:`审核模式`(全部要审 / 全部免审)+ `免审智能体` + `免审类型` + `回收保留天数`。
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
176
189
|
## 🧬 为什么全自研
|
|
177
190
|
|
|
178
191
|
市面上记忆方案多,但大多依赖第三方框架 / 动不动起 MCP 服务 / 记忆锁私有库。本插件把骨架自己搭,**零第三方运行时依赖**,逻辑逐行可读:
|
package/index.js
CHANGED
|
@@ -91,7 +91,7 @@ export const Config = z.object({
|
|
|
91
91
|
|
|
92
92
|
const API_PREFIX = '/memory-eternal/api'
|
|
93
93
|
// DSH 宿主自动沉淀卡的署名:用可读名而非 agent 会话 id,便于在智能体筛选中归组。
|
|
94
|
-
const DSH_AGENT = '
|
|
94
|
+
const DSH_AGENT = 'deepseek-harness'
|
|
95
95
|
|
|
96
96
|
export function apply(ctx, config) {
|
|
97
97
|
const settings = ctx.settings.register('memory-eternal', Config, { base: config ?? {} })
|
|
@@ -124,6 +124,15 @@ export function apply(ctx, config) {
|
|
|
124
124
|
}
|
|
125
125
|
return roots
|
|
126
126
|
}
|
|
127
|
+
// 把完整配置写入共享文件,使独立 web / MCP hook 捕获与 DSH 设置同步(不同步修复)。
|
|
128
|
+
const syncConfigFile = async () => {
|
|
129
|
+
try {
|
|
130
|
+
const cfg = settings.get() ?? {}
|
|
131
|
+
const { configFilePath } = await import('./lib/capture-run.js')
|
|
132
|
+
await (await import('node:fs')).promises.writeFile(configFilePath(process.env), JSON.stringify(cfg, null, 2), 'utf8')
|
|
133
|
+
} catch { /* 静默 */ }
|
|
134
|
+
}
|
|
135
|
+
syncConfigFile()
|
|
127
136
|
// agent/turn-stopping 是 serial 事件:不在监听器里 await LLM(会拖慢收尾),
|
|
128
137
|
// 同步抓取增量事件快照后,把真正的捕获调度到后台队列执行。
|
|
129
138
|
const pending = new Map() // sessionId -> merged events array
|
|
@@ -413,7 +422,7 @@ export function apply(ctx, config) {
|
|
|
413
422
|
vaultDir: vaultDir(),
|
|
414
423
|
version: versionRef,
|
|
415
424
|
}
|
|
416
|
-
return json(res, 200, { ok: true, config: safe, revision: me?.revision ?? 0, schema: me?.schema ?? null, dsh: dshInfo, version: versionRef })
|
|
425
|
+
return json(res, 200, { ok: true, config: safe, revision: me?.revision ?? 0, writable: true, readonly: false, schema: me?.schema ?? null, dsh: dshInfo, version: versionRef })
|
|
417
426
|
}
|
|
418
427
|
if (method === 'POST') {
|
|
419
428
|
let raw = ''
|
|
@@ -430,6 +439,8 @@ export function apply(ctx, config) {
|
|
|
430
439
|
if (typeof settings.update === 'function') {
|
|
431
440
|
try {
|
|
432
441
|
await settings.update(clean)
|
|
442
|
+
// 把完整配置写入共享文件,让独立 web / MCP hook 与 DSH 设置同步(不同步修复)
|
|
443
|
+
syncConfigFile()
|
|
433
444
|
return json(res, 200, { ok: true, applied: Object.keys(clean), note: '已保存。autoWebMode/watchdogAutoSpawn 等需重启 DSH 生效' })
|
|
434
445
|
} catch (e) {
|
|
435
446
|
if (e && e.code === 'SETTINGS_CONFLICT') return json(res, 409, { ok: false, error: '配置已被外部修改,请刷新后重试(revision conflict)' })
|
package/lib/api.js
CHANGED
|
@@ -38,8 +38,11 @@ export function createApi(deps = {}) {
|
|
|
38
38
|
case '/cards': {
|
|
39
39
|
const kind = query.get('kind') || ''
|
|
40
40
|
const q = query.get('q') || ''
|
|
41
|
+
const status = (query.get('status') || 'approved').toLowerCase()
|
|
41
42
|
const limit = Math.min(Number(query.get('limit')) || 200, 500)
|
|
42
|
-
|
|
43
|
+
// all = 全部(含 pending/rejected,排除回收站);默认/approved = 已审核。
|
|
44
|
+
const want = status === 'all' ? ['approved', 'pending', 'rejected'] : status === 'pending' || status === 'rejected' ? [status] : ['approved']
|
|
45
|
+
let cards = await listCards(vaultRoot, { status: want })
|
|
43
46
|
if (kind) cards = cards.filter((c) => c.kind === kind)
|
|
44
47
|
if (q.trim()) {
|
|
45
48
|
const hits = await search(vaultRoot, q, { limit: 200 })
|
|
@@ -166,7 +169,7 @@ export function createApi(deps = {}) {
|
|
|
166
169
|
const text = c.text || ''
|
|
167
170
|
let kind = c.kind || 'knowledge', title = c.title || '导入记忆', tags = [], body = text, source = ''
|
|
168
171
|
try { const p = parseCard(text); kind = p.meta.kind || kind; title = p.meta.title || title; tags = p.meta.tags || tags; body = p.body; source = p.meta.source } catch {}
|
|
169
|
-
const r = await writeCard(vaultRoot, { kind, title, tags, body, source })
|
|
172
|
+
const r = await writeCard(vaultRoot, { kind, title, tags, body, source, status: 'pending' })
|
|
170
173
|
if (r.ok) imported++; else skipped++
|
|
171
174
|
}
|
|
172
175
|
json(res, 200, { ok: true, imported, skipped })
|
|
@@ -278,7 +281,7 @@ export function createApi(deps = {}) {
|
|
|
278
281
|
autoWeb: cfg.autoWeb ?? env.MEMORY_AUTO_WEB !== '0', autoWebMode: cfg.autoWebMode || 'init', webPort: Number(cfg.webPort) || Number(env.MEMORY_WEB_PORT) || 7999, webCheckIntervalMs: Number(cfg.webCheckIntervalMs) || 5000, webMaxRestart: Number(cfg.webMaxRestart) || 10, watchdogAutoSpawn: cfg.watchdogAutoSpawn ?? env.MEMORY_WATCHDOG === '1', autoMcpSetup: cfg.autoMcpSetup ?? false,
|
|
279
282
|
auditMode: cfg.auditMode ?? 'all', auditExemptAgents: cfg.auditExemptAgents ?? [], auditExemptKinds: cfg.auditExemptKinds ?? [], recycleRetentionDays: cfg.recycleRetentionDays ?? 30,
|
|
280
283
|
}
|
|
281
|
-
json(res, 200, { ok: true, config: safe, revision: 0, version: env.MEMORY_ETERNAL_VERSION || '' })
|
|
284
|
+
json(res, 200, { ok: true, config: safe, revision: 0, writable: false, readonly: true, version: env.MEMORY_ETERNAL_VERSION || '' })
|
|
282
285
|
return
|
|
283
286
|
}
|
|
284
287
|
case '/compress': {
|
package/lib/capture-run.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import path from 'node:path'
|
|
9
9
|
import os from 'node:os'
|
|
10
|
+
import fs from 'node:fs'
|
|
10
11
|
import { captureCard, captureUpdate, pickNeighbors, summarizeTurn } from './capture.js'
|
|
11
12
|
import { createLlmFromEnv } from './llm-openai.js'
|
|
12
13
|
|
|
@@ -16,6 +17,18 @@ export function defaultVaultDir(env = process.env) {
|
|
|
16
17
|
return path.join(home, 'memory-vault')
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
// 读取 DSH 设置的完整配置(写入的共享文件),使独立 web / MCP hook 捕获与 DSH 设置同步。
|
|
21
|
+
const CONFIG_FILE = 'memory-eternal-config.json'
|
|
22
|
+
export function configFilePath(env = process.env) {
|
|
23
|
+
return path.join(env.DSH_HOME || path.join(os.homedir(), '.dsh'), CONFIG_FILE)
|
|
24
|
+
}
|
|
25
|
+
function readConfig(env = process.env) {
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(fs.readFileSync(configFilePath(env), 'utf8'))
|
|
28
|
+
} catch { return null }
|
|
29
|
+
}
|
|
30
|
+
function splitList(x) { return (Array.isArray(x) ? x : String(x || '').split(',')).map((s) => String(s).trim()).filter(Boolean) }
|
|
31
|
+
|
|
19
32
|
/**
|
|
20
33
|
* 沉淀一段对话文本到 vault。
|
|
21
34
|
* @returns {Promise<{ok:boolean, action:'created'|'appended'|'skipped'|'failed', path?:string, reason?:string, degraded?:boolean}>}
|
|
@@ -24,13 +37,15 @@ export async function runStandaloneCapture(vaultRoot, text, { source = '', llm,
|
|
|
24
37
|
const clean = String(text || '').trim()
|
|
25
38
|
if (clean.length < minChars) return { ok: false, action: 'skipped', reason: 'text too short' }
|
|
26
39
|
|
|
27
|
-
//
|
|
40
|
+
// 自动审核:共享配置文件(DSH)优先,其次 env,默认 all(独立进程无 DSH settings)
|
|
28
41
|
const resolveAuditStatus = (kind, sub) => {
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
if (
|
|
42
|
+
const shared = readConfig(env)
|
|
43
|
+
const mode = shared?.auditMode || env.MEMORY_AUDIT_MODE || 'all'
|
|
44
|
+
const agents = shared?.auditExemptAgents ? splitList(shared.auditExemptAgents) : splitList(env.MEMORY_AUDIT_EXEMPT_AGENTS || '')
|
|
45
|
+
const kinds = shared?.auditExemptKinds ? splitList(shared.auditExemptKinds) : splitList(env.MEMORY_AUDIT_EXEMPT_KINDS || '')
|
|
46
|
+
if (mode === 'none') return 'approved'
|
|
47
|
+
if (agents.includes('__all__') || agents.includes(sub)) return 'approved'
|
|
48
|
+
if (kinds.includes('__all__') || kinds.includes(kind)) return 'approved'
|
|
34
49
|
return 'pending'
|
|
35
50
|
}
|
|
36
51
|
|