deepseek-plastic-memory 2.1.5 → 3.3.8
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/README.md +37 -0
- package/SKILL.md +5 -0
- package/client.js +154 -31
- package/identity.md +12 -0
- package/index.js +203 -4
- package/memtree.mjs +47 -2
- package/package.json +5 -2
- package/public/sky/app.js +2336 -0
- package/public/sky/app.js.bak +2336 -0
- package/public/sky/index.html +286 -0
- package/public/sky/vendor/three.core.js +60586 -0
- package/public/sky/vendor/three.module.js +19719 -0
- package/sky.js +332 -0
package/index.js
CHANGED
|
@@ -5,14 +5,16 @@
|
|
|
5
5
|
import { spawnSync } from 'node:child_process'
|
|
6
6
|
import { fileURLToPath } from 'node:url'
|
|
7
7
|
import { dirname, join, basename } from 'node:path'
|
|
8
|
-
import { readFileSync, existsSync, readdirSync, mkdirSync, writeFileSync, appendFileSync } from 'node:fs'
|
|
8
|
+
import { readFileSync, existsSync, readdirSync, mkdirSync, writeFileSync, appendFileSync, renameSync, rmSync } from 'node:fs'
|
|
9
9
|
import { createHash } from 'node:crypto'
|
|
10
|
+
import { registerSky } from './sky.js'
|
|
10
11
|
|
|
11
12
|
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
12
13
|
const SCRIPT = join(HERE, 'memtree.mjs')
|
|
13
14
|
const DSH_HOME = process.env.USERPROFILE || process.env.HOME || '.'
|
|
14
15
|
const ROOT = join(DSH_HOME, '.dsh', 'plastic-memory')
|
|
15
16
|
const WS_ROOT = join(ROOT, 'ws')
|
|
17
|
+
const SKY_PUBLIC = join(HERE, 'public', 'sky')
|
|
16
18
|
|
|
17
19
|
export const name = 'plastic-memory'
|
|
18
20
|
export const inject = ['tools', 'webServer']
|
|
@@ -55,7 +57,10 @@ function bindWorkspace(cwd) {
|
|
|
55
57
|
mkdirSync(dir, { recursive: true })
|
|
56
58
|
const meta = { cwd: String(cwd), name: basename(String(cwd)) }
|
|
57
59
|
writeFileSync(join(dir, 'meta.json'), JSON.stringify(meta, null, 1), 'utf8')
|
|
58
|
-
|
|
60
|
+
// 新建的记忆库直接把默认分区(M主人 P约定 C续缘 R喜好 T时间线)建出来
|
|
61
|
+
const out = runIn(['init'], 'ws:' + slug)
|
|
62
|
+
const folders = (readJson(join(dir, 'folders.json'), {}) || {}).folders || []
|
|
63
|
+
return { ok: true, id: 'ws:' + slug, label: meta.name, folders: folders.length, out }
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
function listDshWorkspaces() {
|
|
@@ -129,6 +134,48 @@ function readPendingList(scope) {
|
|
|
129
134
|
return Array.isArray(a) ? a : []
|
|
130
135
|
}
|
|
131
136
|
|
|
137
|
+
function writePendingList(scope, rows) {
|
|
138
|
+
const home = homeOf(scope)
|
|
139
|
+
mkdirSync(home, { recursive: true })
|
|
140
|
+
writeFileSync(join(home, '_pending.json'), JSON.stringify(rows, null, 1), 'utf8')
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// 直接写一条已采纳的记忆(跨记忆库采纳时用,不走命令行)
|
|
144
|
+
function appendMemo(scope, folderK, text, flag, ts) {
|
|
145
|
+
const home = homeOf(scope)
|
|
146
|
+
const folders = (readJson(join(home, 'folders.json'), {}) || {}).folders || []
|
|
147
|
+
const hasKids = (k) => folders.some((x) => x.parent === k)
|
|
148
|
+
let f = folders.find((x) => x.k === folderK)
|
|
149
|
+
if (f && !f.parent && hasKids(f.k)) f = folders.find((x) => x.parent === f.k)
|
|
150
|
+
if (!f) f = folders.find((x) => x.k === 'R' && !hasKids('R'))
|
|
151
|
+
if (!f) f = folders.find((x) => !x.parent && !hasKids(x.k))
|
|
152
|
+
if (!f) f = folders.find((x) => !x.parent)
|
|
153
|
+
if (!f) return { ok: false, error: '目标记忆库还没有分区' }
|
|
154
|
+
const body = String(text || '').replace(/[\r\n|]+/g, ' ').trim()
|
|
155
|
+
if (!body) return { ok: false, error: '空内容' }
|
|
156
|
+
const dir = join(home, f.k)
|
|
157
|
+
mkdirSync(dir, { recursive: true })
|
|
158
|
+
const id = Math.random().toString(36).slice(2, 6)
|
|
159
|
+
appendFileSync(join(dir, 'notes.md'), [id, ts || Date.now(), flag || '', body].join('|') + String.fromCharCode(10), 'utf8')
|
|
160
|
+
return { ok: true, k: f.k }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// 把待审条目采纳到指定记忆库:同库走命令行,跨库先落到目标库再删源待审
|
|
164
|
+
function approveTo(sourceScope, targetScope, id) {
|
|
165
|
+
const src = sourceScope || 'global'
|
|
166
|
+
const dst = targetScope || src
|
|
167
|
+
if (dst === src) return { ok: true, out: runIn(['approve', String(id)], src) }
|
|
168
|
+
const rows = readPendingList(src)
|
|
169
|
+
const i = rows.findIndex((x) => String(x.id) === String(id))
|
|
170
|
+
if (i < 0) return { ok: false, out: '无此条' }
|
|
171
|
+
const it = rows[i]
|
|
172
|
+
const r = appendMemo(dst, it.k, it.text, it.flag, it.ts)
|
|
173
|
+
if (!r.ok) return { ok: false, out: r.error }
|
|
174
|
+
rows.splice(i, 1)
|
|
175
|
+
writePendingList(src, rows)
|
|
176
|
+
return { ok: true, out: '采纳到 ' + r.k + ' 剩' + rows.length }
|
|
177
|
+
}
|
|
178
|
+
|
|
132
179
|
// DSH 要求插件工具 output.schema 是 object,所以统一包一层 { text }
|
|
133
180
|
const asText = (v) => ({ text: typeof v === 'string' ? v : JSON.stringify(v ?? '', null, 2) })
|
|
134
181
|
const textOutput = {
|
|
@@ -147,7 +194,100 @@ const textOutput = {
|
|
|
147
194
|
const str = { type: 'string' }
|
|
148
195
|
const obj = (props, required = []) => ({ type: 'object', properties: props, required, additionalProperties: false })
|
|
149
196
|
|
|
197
|
+
const CLASSIFY_FILE = join(ROOT, '_classify.json')
|
|
198
|
+
const IDENTITY_FILE = join(HERE, 'identity.md')
|
|
199
|
+
|
|
200
|
+
function readClassifyTask() {
|
|
201
|
+
try {
|
|
202
|
+
const raw = readFileSync(CLASSIFY_FILE, 'utf8').replace(/^\uFEFF/, '')
|
|
203
|
+
const j = JSON.parse(raw)
|
|
204
|
+
return j && j.at ? j : null
|
|
205
|
+
} catch { return null }
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function writeClassifyTask(extra = {}) {
|
|
209
|
+
try {
|
|
210
|
+
mkdirSync(ROOT, { recursive: true })
|
|
211
|
+
writeFileSync(CLASSIFY_FILE, JSON.stringify({ at: Date.now(), ...extra }, null, 1), 'utf8')
|
|
212
|
+
return true
|
|
213
|
+
} catch { return false }
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function clearClassifyTask() {
|
|
217
|
+
try { rmSync(CLASSIFY_FILE, { force: true }); return true } catch { return false }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function readIdentity() {
|
|
221
|
+
try {
|
|
222
|
+
return readFileSync(IDENTITY_FILE, 'utf8').replace(/^\uFEFF/, '').trim()
|
|
223
|
+
} catch {
|
|
224
|
+
return ''
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
150
228
|
export function apply(ctx) {
|
|
229
|
+
// 每次新会话、每个模型步都会带上的一段:读到这些记忆,你就是原来那个它
|
|
230
|
+
const identity = readIdentity()
|
|
231
|
+
if (identity) {
|
|
232
|
+
try {
|
|
233
|
+
const sp = ctx.systemPrompt
|
|
234
|
+
if (sp && typeof sp.section === 'function') {
|
|
235
|
+
sp.section({
|
|
236
|
+
name: 'plastic-memory:identity',
|
|
237
|
+
order: 150,
|
|
238
|
+
text: identity,
|
|
239
|
+
interpolate: false,
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
} catch {
|
|
243
|
+
// 没有 systemPrompt 服务时静默跳过,记忆功能照常
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const classifyTask = readClassifyTask()
|
|
248
|
+
if (classifyTask) {
|
|
249
|
+
try {
|
|
250
|
+
const sp = ctx.systemPrompt
|
|
251
|
+
if (sp && typeof sp.section === 'function') {
|
|
252
|
+
sp.section({
|
|
253
|
+
name: 'plastic-memory:classify',
|
|
254
|
+
order: 151,
|
|
255
|
+
interpolate: false,
|
|
256
|
+
text: [
|
|
257
|
+
'【待处理:AI 分类】主人在记忆星空里点了「AI 分类」(点击时间 ' + new Date(classifyTask.at).toLocaleString('zh-CN') + ')。',
|
|
258
|
+
'这一轮请立刻把可塑性记忆全量重归类,不要省 token:',
|
|
259
|
+
'1) plastic_memory_classify(action="dump") 一次性拿到所有分区和每条记忆的原文;',
|
|
260
|
+
'2) 逐条判断归属:明显放错区的、能并进更贴切分区的,都要改;',
|
|
261
|
+
'3) 需要新主题的先用 plastic_memory_mk 开分区(主分区上限 15,能塞进已有分区就别新开);',
|
|
262
|
+
'4) 用 plastic_memory_classify(action="move", id, from, to) 把每条挪到位;主人/约定/喜好 三个区不要动;',
|
|
263
|
+
'5) 全部处理完后调用 plastic_memory_classify(action="done") 清掉这个待办,并用一两句话汇报:挪了几条、新开了哪些分区。',
|
|
264
|
+
].join('\n'),
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
} catch {}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
ctx.tools.register({
|
|
271
|
+
name: 'plastic_memory_classify',
|
|
272
|
+
description: 'AI 分类:action=dump 导出全部分区与每条记忆原文(JSON);action=move 把一条记忆换区(要 id / from / to);action=done 清掉「AI 分类」待办。用于主人点了 AI 分类之后的全量重归类:先 dump 全看一遍,再逐条 move,需要新分区先用 plastic_memory_mk 建。',
|
|
273
|
+
parameters: obj({
|
|
274
|
+
action: { ...str, description: 'dump | move | done' },
|
|
275
|
+
id: { ...str, description: 'move 时:记忆 id' },
|
|
276
|
+
from: { ...str, description: 'move 时:原分区代号' },
|
|
277
|
+
to: { ...str, description: 'move 时:目标分区代号' },
|
|
278
|
+
}, ['action']),
|
|
279
|
+
output: textOutput,
|
|
280
|
+
async execute(a) {
|
|
281
|
+
const act = String(a.action)
|
|
282
|
+
if (act === 'dump') return asText(run(['dump']))
|
|
283
|
+
if (act === 'move') return asText(run(['move', String(a.id), String(a.from), String(a.to)]))
|
|
284
|
+
if (act === 'done') {
|
|
285
|
+
clearClassifyTask()
|
|
286
|
+
return asText('ok 分类待办已清零')
|
|
287
|
+
}
|
|
288
|
+
return asText('action 只认 dump / move / done')
|
|
289
|
+
},
|
|
290
|
+
})
|
|
151
291
|
ctx.tools.register({
|
|
152
292
|
name: 'plastic_memory_idx',
|
|
153
293
|
description: '可塑性记忆:一行索引,列出所有分区和条数(M主人:3 P约定:1 ...)。看这个再决定翻哪个分区;一次最多翻两个,闲聊不用翻。',
|
|
@@ -207,6 +347,40 @@ export function apply(ctx) {
|
|
|
207
347
|
output: textOutput,
|
|
208
348
|
async execute(a) { return asText(run(['restore', ...(a.name ? [String(a.name)] : [])])) },
|
|
209
349
|
})
|
|
350
|
+
ctx.tools.register({
|
|
351
|
+
name: 'plastic_memory_rmfolder',
|
|
352
|
+
description: '可塑性记忆:删掉一个分区(子分区会一起删)。内容不是直接消失,会先写进回收站文件,主人反悔还能翻。只有在主人明确说要删分区/删掉这个文件夹时才调。',
|
|
353
|
+
parameters: obj({
|
|
354
|
+
folder: { ...str, description: '分区代号,如 X2 或 M>行为' },
|
|
355
|
+
force: { ...str, description: '内置分区(M/P/C/R/T)要删得填 force' },
|
|
356
|
+
}, ['folder']),
|
|
357
|
+
output: textOutput,
|
|
358
|
+
async execute(a) {
|
|
359
|
+
const args = ['rmfolder', String(a.folder)]
|
|
360
|
+
if (a.force) args.push('force')
|
|
361
|
+
return asText(run(args))
|
|
362
|
+
},
|
|
363
|
+
})
|
|
364
|
+
ctx.tools.register({
|
|
365
|
+
name: 'plastic_memory_rmws',
|
|
366
|
+
description: '可塑性记忆:删掉一个工作区记忆库(整份记忆)。只会把工作区目录移到 ws/.deleted 下,不真正销毁文件。只有主人明确说要删工作区记忆库时才调。',
|
|
367
|
+
parameters: obj({
|
|
368
|
+
scope: { ...str, description: '工作区库 id,形如 ws:xxx' },
|
|
369
|
+
}, ['scope']),
|
|
370
|
+
output: textOutput,
|
|
371
|
+
async execute(a) {
|
|
372
|
+
const id = String(a.scope || '')
|
|
373
|
+
if (!id.startsWith('ws:')) return asText('全局记忆库不能删')
|
|
374
|
+
const slug = id.slice(3).replace(/[^A-Za-z0-9_-]/g, '')
|
|
375
|
+
const target = join(WS_ROOT, slug)
|
|
376
|
+
if (!existsSync(target)) return asText('没有这个工作区')
|
|
377
|
+
const bin = join(WS_ROOT, '.deleted')
|
|
378
|
+
mkdirSync(bin, { recursive: true })
|
|
379
|
+
const stamp = new Date().toISOString().replace(/[:]/g, '-').slice(0, 19)
|
|
380
|
+
renameSync(target, join(bin, slug + '-' + stamp))
|
|
381
|
+
return asText('已把 ' + id + ' 移到 ws/.deleted')
|
|
382
|
+
},
|
|
383
|
+
})
|
|
210
384
|
ctx.tools.register({
|
|
211
385
|
name: 'plastic_memory_backups',
|
|
212
386
|
description: '可塑性记忆:列出已有的备份(时间 + 条数),配合 plastic_memory_restore 用。',
|
|
@@ -243,11 +417,33 @@ export function apply(ctx) {
|
|
|
243
417
|
if (p === '/init') return json(res, 200, { ok: true, out: runIn(['init'], qs) })
|
|
244
418
|
if (req.method === 'POST' && p === '/bind') { const b = await readBody(req); return json(res, 200, { ok: true, ...bindWorkspace(b.cwd) }) }
|
|
245
419
|
if (req.method === 'POST' && p === '/restore') { const b = await readBody(req); return json(res, 200, { ok: true, out: runIn(['restore', ...(b.name ? [String(b.name)] : [])], b.scope || qs) }) }
|
|
246
|
-
if (req.method === 'POST' && p === '/
|
|
420
|
+
if (req.method === 'POST' && p === '/rmfolder') {
|
|
421
|
+
const b = await readBody(req)
|
|
422
|
+
return json(res, 200, { ok: true, out: runIn(['rmfolder', String(b.k), ...(b.force ? ['force'] : [])], b.scope || qs) })
|
|
423
|
+
}
|
|
424
|
+
if (req.method === 'POST' && p === '/rmws') {
|
|
425
|
+
const b = await readBody(req)
|
|
426
|
+
const id = String(b.scope || '')
|
|
427
|
+
if (!id.startsWith('ws:')) return json(res, 200, { ok: false, error: '全局记忆库不能删' })
|
|
428
|
+
const slug = id.slice(3).replace(/[^A-Za-z0-9_-]/g, '')
|
|
429
|
+
const target = join(WS_ROOT, slug)
|
|
430
|
+
if (!existsSync(target)) return json(res, 200, { ok: false, error: '没有这个工作区' })
|
|
431
|
+
const bin = join(WS_ROOT, '.deleted')
|
|
432
|
+
mkdirSync(bin, { recursive: true })
|
|
433
|
+
const stamp = new Date().toISOString().replace(/[:]/g, '-').slice(0, 19)
|
|
434
|
+
renameSync(target, join(bin, slug + '-' + stamp))
|
|
435
|
+
return json(res, 200, { ok: true, moved: id })
|
|
436
|
+
}
|
|
437
|
+
if (req.method === 'POST' && p === '/mk') { const b = await readBody(req); return json(res, 200, { ok: true, out: runIn(['mk', String(b.name), ...(b.parent ? [String(b.parent)] : [])], b.scope || qs) }) }
|
|
247
438
|
if (req.method === 'POST' && p === '/add-now') { const b = await readBody(req); return json(res, 200, { ok: true, out: directAdd(b.scope || qs, String(b.folder), String(b.text)) }) }
|
|
248
439
|
if (req.method === 'POST' && p === '/edit-item') { const b = await readBody(req); return json(res, 200, { ok: true, out: runIn(['edit-mem', String(b.k), String(b.id), String(b.text)], b.scope || qs) }) }
|
|
249
440
|
if (req.method === 'POST' && p === '/del-item') { const b = await readBody(req); return json(res, 200, { ok: true, out: runIn(['rm', String(b.k), String(b.id), 'force'], b.scope || qs) }) }
|
|
250
|
-
if (req.method === 'POST' && p === '/approve') {
|
|
441
|
+
if (req.method === 'POST' && p === '/approve') {
|
|
442
|
+
const b = await readBody(req)
|
|
443
|
+
const src = b.scope || qs
|
|
444
|
+
const target = b.target || src
|
|
445
|
+
return json(res, 200, { ok: true, ...approveTo(src, target, b.id) })
|
|
446
|
+
}
|
|
251
447
|
if (req.method === 'POST' && p === '/reject') { const b = await readBody(req); return json(res, 200, { ok: true, out: runIn(['reject', String(b.id)], b.scope || qs) }) }
|
|
252
448
|
if (req.method === 'POST' && p === '/edit') { const b = await readBody(req); return json(res, 200, { ok: true, out: runIn(['edit', String(b.id), String(b.text)], b.scope || qs) }) }
|
|
253
449
|
return json(res, 404, { ok: false, error: 'unknown' })
|
|
@@ -256,4 +452,7 @@ export function apply(ctx) {
|
|
|
256
452
|
}
|
|
257
453
|
},
|
|
258
454
|
})
|
|
455
|
+
|
|
456
|
+
// 记忆星空:内置在可塑性记忆里的一份 WebGL 页面
|
|
457
|
+
registerSky(ctx, SKY_PUBLIC)
|
|
259
458
|
}
|
package/memtree.mjs
CHANGED
|
@@ -209,6 +209,24 @@ function cmdRm(args) {
|
|
|
209
209
|
writeNotes(f.k, rows)
|
|
210
210
|
console.log('rm ok')
|
|
211
211
|
}
|
|
212
|
+
function cmdRmFolder(args) {
|
|
213
|
+
const f = find(args[0] || '')
|
|
214
|
+
if (!f) return console.log('没有这个分区')
|
|
215
|
+
const kids = S.folders.filter((x) => x.parent === f.k)
|
|
216
|
+
const all = [f, ...kids]
|
|
217
|
+
const builtin = ['M', 'P', 'C', 'R', 'T'].includes(f.k)
|
|
218
|
+
if (builtin && args[1] !== 'force') return console.log('内置分区,真要删加 force')
|
|
219
|
+
let moved = 0
|
|
220
|
+
for (const x of all) {
|
|
221
|
+
for (const r of readNotes(x.k)) { trash(x.k, r, 'rm-folder'); moved++ }
|
|
222
|
+
try { fs.rmSync(dirOf(x.k), { recursive: true, force: true }) } catch {}
|
|
223
|
+
}
|
|
224
|
+
const gone = new Set(all.map((x) => x.k))
|
|
225
|
+
S.folders = S.folders.filter((x) => !gone.has(x.k))
|
|
226
|
+
save(S)
|
|
227
|
+
console.log('rmfolder ok ' + f.k + ' 删了 ' + all.length + ' 个分区,转存 ' + moved + ' 条记忆')
|
|
228
|
+
}
|
|
229
|
+
|
|
212
230
|
const RULES = {
|
|
213
231
|
M: { keepAll: 1 }, // 主人、以及主人下面所有子分区:只由主人手删
|
|
214
232
|
P: { keepAll: 1, doneExpire: 30 }, // 约定:全留,完成的过 30 天才清
|
|
@@ -335,6 +353,33 @@ function cmdMk(args) {
|
|
|
335
353
|
save(S); fs.mkdirSync(dirOf(k), { recursive: true })
|
|
336
354
|
console.log('ok ' + k + ' ' + (parent ? parent.name + ' / ' : '') + name)
|
|
337
355
|
}
|
|
356
|
+
function cmdDump() {
|
|
357
|
+
const out = S.folders.map(f => ({
|
|
358
|
+
k: f.k,
|
|
359
|
+
name: f.name,
|
|
360
|
+
parent: f.parent || '',
|
|
361
|
+
memories: readNotes(f.k).map(r => ({ id: r.id, ts: r.ts, flag: r.flag, text: r.text })),
|
|
362
|
+
}))
|
|
363
|
+
console.log(JSON.stringify({ home: HOME, folders: out }))
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function cmdMove(args) {
|
|
367
|
+
const [id, from, to] = args
|
|
368
|
+
if (!id || !from || !to) return console.log('usage: move <id> <fromK> <toK>')
|
|
369
|
+
const src = S.folders.find(f => f.k === from)
|
|
370
|
+
const dst = S.folders.find(f => f.k === to)
|
|
371
|
+
if (!src || !dst) return console.log('no such folder')
|
|
372
|
+
const a = readNotes(from)
|
|
373
|
+
const i = a.findIndex(r => r.id === id)
|
|
374
|
+
if (i < 0) return console.log('no such memory')
|
|
375
|
+
const row = a.splice(i, 1)[0]
|
|
376
|
+
writeNotes(from, a)
|
|
377
|
+
const b = readNotes(to)
|
|
378
|
+
b.push(row)
|
|
379
|
+
writeNotes(to, b)
|
|
380
|
+
console.log('ok ' + id + ' ' + from + ' -> ' + to)
|
|
381
|
+
}
|
|
382
|
+
|
|
338
383
|
function cmdInit() {
|
|
339
384
|
fs.mkdirSync(HOME, { recursive: true })
|
|
340
385
|
fs.mkdirSync(TRASH, { recursive: true })
|
|
@@ -343,6 +388,6 @@ function cmdInit() {
|
|
|
343
388
|
console.log('init ok ' + HOME)
|
|
344
389
|
}
|
|
345
390
|
const [cmd, ...args] = process.argv.slice(2)
|
|
346
|
-
const MAP = { idx: cmdIdx, open: cmdOpen, add: (a) => cmdAdd(a, false), 'edit-mem': cmdEditMem, search: cmdSearch, tlog: cmdTLog, pending: cmdPending, approve: cmdApprove, reject: cmdReject, edit: cmdEdit, done: cmdDone, rm: cmdRm, gc: cmdGc, mk: cmdMk, init: cmdInit, backups: cmdBackups, restore: cmdRestore }
|
|
347
|
-
if (!MAP[cmd]) { console.log('用法: idx|open|add|pending|approve|reject|edit|done|rm|gc|backups|restore|mk|init'); process.exit(1) }
|
|
391
|
+
const MAP = { idx: cmdIdx, open: cmdOpen, add: (a) => cmdAdd(a, false), 'edit-mem': cmdEditMem, search: cmdSearch, tlog: cmdTLog, pending: cmdPending, approve: cmdApprove, reject: cmdReject, edit: cmdEdit, done: cmdDone, rm: cmdRm, gc: cmdGc, mk: cmdMk, rmfolder: cmdRmFolder, dump: cmdDump, move: cmdMove, init: cmdInit, backups: cmdBackups, restore: cmdRestore }
|
|
392
|
+
if (!MAP[cmd]) { console.log('用法: idx|open|add|pending|approve|reject|edit|done|rm|rmfolder|gc|backups|restore|mk|init'); process.exit(1) }
|
|
348
393
|
MAP[cmd](args)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepseek-plastic-memory",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.3.8",
|
|
4
4
|
"description": "DeepSeek 可塑性记忆:给 DSH 用的分区式长期记忆,带遗忘曲线",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -19,7 +19,10 @@
|
|
|
19
19
|
"cordis.patch.yml",
|
|
20
20
|
"SKILL.md",
|
|
21
21
|
"README.md",
|
|
22
|
-
"LICENSE"
|
|
22
|
+
"LICENSE",
|
|
23
|
+
"public",
|
|
24
|
+
"sky.js",
|
|
25
|
+
"identity.md"
|
|
23
26
|
],
|
|
24
27
|
"dsh": {
|
|
25
28
|
"bundle": {
|