deepseek-plastic-memory 3.3.8 → 3.4.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/SKILL.md +6 -5
- package/index.js +8 -1
- package/memtree.mjs +22 -1
- package/package.json +1 -1
- package/public/sky/app.js +16 -4
- package/public/sky/app.js.bak +16 -4
package/SKILL.md
CHANGED
|
@@ -28,7 +28,8 @@ description: 可塑性记忆(Plastic Memory)—— 按可自由扩展的子
|
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
N=<node 绝对路径>; M=~/.dsh/plastic-memory/memtree.mjs
|
|
31
|
-
$N $M
|
|
31
|
+
$N $M all # 一次性读出全部记忆(默认用这个)
|
|
32
|
+
$N $M idx # 一行索引:分区 + 条数(只想看结构时用)
|
|
32
33
|
$N $M open M # 翻一个分区:id 天数 标记 内容
|
|
33
34
|
$N $M add M 爱吃辣 # 提交一条待审(能短则短)
|
|
34
35
|
$N $M add-now M 爱吃辣 # 直接写入,跳过审批(自己写用)
|
|
@@ -120,11 +121,11 @@ $N $M tlog 修了崩溃问题
|
|
|
120
121
|
- 一天最多 5 条左右,超了就先挑最值的
|
|
121
122
|
- 记完别汇报"已保存",随口带一句"这个记下了"就够了
|
|
122
123
|
|
|
123
|
-
##
|
|
124
|
+
## 回答前怎么读记忆
|
|
124
125
|
|
|
125
|
-
|
|
126
|
+
**默认全量读**:直接 `plastic_memory_all`(或 `$N $M all`)把每个分区都读一遍,再从里面找要用的。不要先 `idx` 再挑分区,也不要只翻一两个区。
|
|
126
127
|
|
|
127
|
-
| 他问的 |
|
|
128
|
+
| 他问的 | 重点看哪个区 |
|
|
128
129
|
| --- | --- |
|
|
129
130
|
| 我是谁 / 我住哪 / 我的情况 | `M`,不够再看 `M>行为` |
|
|
130
131
|
| 我们约过什么 / 你答应我的 | `P` |
|
|
@@ -133,7 +134,7 @@ $N $M tlog 修了崩溃问题
|
|
|
133
134
|
| 最近发生过什么 | `T` |
|
|
134
135
|
| 工作、项目上的事 | `X0 工作` 或工作区记忆库 |
|
|
135
136
|
|
|
136
|
-
|
|
137
|
+
**规矩:需要回忆就读全部,不缺这点 token。** 全量读完再按上表心里过一遍,比反复挑分区翻错更省事。闲聊、打招呼、单纯接梗——不用读,直接聊。
|
|
137
138
|
|
|
138
139
|
## 换缸提示
|
|
139
140
|
|
package/index.js
CHANGED
|
@@ -288,9 +288,16 @@ export function apply(ctx) {
|
|
|
288
288
|
return asText('action 只认 dump / move / done')
|
|
289
289
|
},
|
|
290
290
|
})
|
|
291
|
+
ctx.tools.register({
|
|
292
|
+
name: 'plastic_memory_all',
|
|
293
|
+
description: '可塑性记忆:一次性读出全部记忆(所有分区 + 待审),直接从这一份里找你需要的东西,不要再用 idx 挑分区。每次需要回忆主人信息/约定/上次聊到哪,都先调这个全量读一遍。',
|
|
294
|
+
parameters: obj({}),
|
|
295
|
+
output: textOutput,
|
|
296
|
+
async execute() { return asText(run(['all'])) },
|
|
297
|
+
})
|
|
291
298
|
ctx.tools.register({
|
|
292
299
|
name: 'plastic_memory_idx',
|
|
293
|
-
description: '
|
|
300
|
+
description: '可塑性记忆:一行索引,只列分区和条数(想看结构时用)。要看内容请直接用 plastic_memory_all 全量读,不要靠 idx 挑分区。',
|
|
294
301
|
parameters: obj({}),
|
|
295
302
|
output: textOutput,
|
|
296
303
|
async execute() { return asText(run(['idx'])) },
|
package/memtree.mjs
CHANGED
|
@@ -380,6 +380,27 @@ function cmdMove(args) {
|
|
|
380
380
|
console.log('ok ' + id + ' ' + from + ' -> ' + to)
|
|
381
381
|
}
|
|
382
382
|
|
|
383
|
+
function cmdAll() {
|
|
384
|
+
const out = []
|
|
385
|
+
for (const f of S.folders) {
|
|
386
|
+
const rows = readNotes(f.k)
|
|
387
|
+
if (!rows.length) continue
|
|
388
|
+
const tag = f.parent ? (S.folders.find(x => x.k === f.parent)?.name || f.parent) + '>' + f.name : f.name
|
|
389
|
+
out.push('## ' + tag + ' (' + f.k + ')')
|
|
390
|
+
for (const r of rows) {
|
|
391
|
+
const flag = r.flag === '*' ? ' [重要]' : r.flag === '✓' ? ' [完成]' : ''
|
|
392
|
+
out.push(r.id + flag + ' ' + r.text)
|
|
393
|
+
}
|
|
394
|
+
out.push('')
|
|
395
|
+
}
|
|
396
|
+
const pend = readPending()
|
|
397
|
+
if (pend.length) {
|
|
398
|
+
out.push('## 待审 (' + pend.length + ' 条)')
|
|
399
|
+
for (const x of pend) out.push(x.id + ' ' + x.text)
|
|
400
|
+
}
|
|
401
|
+
console.log(out.length ? out.join(String.fromCharCode(10)) : '还没有记忆')
|
|
402
|
+
}
|
|
403
|
+
|
|
383
404
|
function cmdInit() {
|
|
384
405
|
fs.mkdirSync(HOME, { recursive: true })
|
|
385
406
|
fs.mkdirSync(TRASH, { recursive: true })
|
|
@@ -388,6 +409,6 @@ function cmdInit() {
|
|
|
388
409
|
console.log('init ok ' + HOME)
|
|
389
410
|
}
|
|
390
411
|
const [cmd, ...args] = process.argv.slice(2)
|
|
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 }
|
|
412
|
+
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, all: cmdAll, init: cmdInit, backups: cmdBackups, restore: cmdRestore }
|
|
392
413
|
if (!MAP[cmd]) { console.log('用法: idx|open|add|pending|approve|reject|edit|done|rm|rmfolder|gc|backups|restore|mk|init'); process.exit(1) }
|
|
393
414
|
MAP[cmd](args)
|
package/package.json
CHANGED
package/public/sky/app.js
CHANGED
|
@@ -1613,26 +1613,30 @@ function applyThemeGlyphs() {
|
|
|
1613
1613
|
|
|
1614
1614
|
function applyDim() {
|
|
1615
1615
|
const sel = state.sel
|
|
1616
|
+
const searching = !!state.query
|
|
1616
1617
|
// 只有选中「星辰」才虚化别的星云;点开一条记忆不动星系明暗
|
|
1617
1618
|
const starSel = sel && (sel.kind === 'main' || sel.kind === 'sub')
|
|
1618
1619
|
const focusK = starSel ? (sel.kind === 'main' ? sel.k : (subs.get(sel.k)?.parentK || '')) : ''
|
|
1619
1620
|
const focusMain = focusK ? (subs.has(focusK) ? subs.get(focusK).parentK : focusK) : ''
|
|
1620
1621
|
|
|
1622
|
+
// 搜索是全局的:不管当前选中了哪个分区,命中的记忆都要亮起来
|
|
1621
1623
|
for (const [k, node] of mains) {
|
|
1624
|
+
if (searching) { node.dimTarget = 0.5; continue }
|
|
1622
1625
|
const related = !focusMain || k === focusMain
|
|
1623
1626
|
node.dimTarget = related ? 1 : 0.16
|
|
1624
1627
|
}
|
|
1625
1628
|
for (const [k, node] of subs) {
|
|
1629
|
+
if (searching) { node.dimTarget = 0.4; continue }
|
|
1626
1630
|
const related = !focusMain || node.parentK === focusMain
|
|
1627
1631
|
const onPath = sel && sel.kind === 'sub' ? sel.k === k : related
|
|
1628
1632
|
node.dimTarget = onPath ? 1 : (related ? 0.55 : 0.12)
|
|
1629
1633
|
}
|
|
1630
|
-
const dimMem = !!focusMain || state.pinnedOnly ||
|
|
1634
|
+
const dimMem = !!focusMain || state.pinnedOnly || searching
|
|
1631
1635
|
const onlyMem = !!(sel && sel.kind === 'mem')
|
|
1632
1636
|
for (const [id, node] of mems) {
|
|
1633
1637
|
let target = 1
|
|
1634
|
-
if (
|
|
1635
|
-
else if (state.
|
|
1638
|
+
if (searching) target = state.matches.has(id) ? 1 : 0.1
|
|
1639
|
+
else if (state.pinnedOnly && !node.mem.pinned) target = 0.15
|
|
1636
1640
|
else if (onlyMem) target = sel.id === id ? 1 : 0.55
|
|
1637
1641
|
else if (focusMain && node.folder !== focusK && !(subs.has(node.folder) && subs.get(node.folder).parentK === focusMain)) target = 0.18
|
|
1638
1642
|
node.dimTarget = dimMem || sel ? target : 1
|
|
@@ -2283,7 +2287,15 @@ async function boot() {
|
|
|
2283
2287
|
} else toast(r.error || '没删掉', 'bad')
|
|
2284
2288
|
})
|
|
2285
2289
|
}
|
|
2286
|
-
$('search').addEventListener('
|
|
2290
|
+
$('search').addEventListener('focus', () => {
|
|
2291
|
+
if (state.sel && state.sel.kind !== 'mem') {
|
|
2292
|
+
state.sel = null
|
|
2293
|
+
applyDim()
|
|
2294
|
+
renderPanel()
|
|
2295
|
+
}
|
|
2296
|
+
})
|
|
2297
|
+
|
|
2298
|
+
$('search').addEventListener('input', (e) => {
|
|
2287
2299
|
clearTimeout(searchTimer)
|
|
2288
2300
|
const v = e.target.value
|
|
2289
2301
|
searchTimer = setTimeout(() => onSearch(v), 130)
|
package/public/sky/app.js.bak
CHANGED
|
@@ -1613,26 +1613,30 @@ function applyThemeGlyphs() {
|
|
|
1613
1613
|
|
|
1614
1614
|
function applyDim() {
|
|
1615
1615
|
const sel = state.sel
|
|
1616
|
+
const searching = !!state.query
|
|
1616
1617
|
// 只有选中「星辰」才虚化别的星云;点开一条记忆不动星系明暗
|
|
1617
1618
|
const starSel = sel && (sel.kind === 'main' || sel.kind === 'sub')
|
|
1618
1619
|
const focusK = starSel ? (sel.kind === 'main' ? sel.k : (subs.get(sel.k)?.parentK || '')) : ''
|
|
1619
1620
|
const focusMain = focusK ? (subs.has(focusK) ? subs.get(focusK).parentK : focusK) : ''
|
|
1620
1621
|
|
|
1622
|
+
// 搜索是全局的:不管当前选中了哪个分区,命中的记忆都要亮起来
|
|
1621
1623
|
for (const [k, node] of mains) {
|
|
1624
|
+
if (searching) { node.dimTarget = 0.5; continue }
|
|
1622
1625
|
const related = !focusMain || k === focusMain
|
|
1623
1626
|
node.dimTarget = related ? 1 : 0.16
|
|
1624
1627
|
}
|
|
1625
1628
|
for (const [k, node] of subs) {
|
|
1629
|
+
if (searching) { node.dimTarget = 0.4; continue }
|
|
1626
1630
|
const related = !focusMain || node.parentK === focusMain
|
|
1627
1631
|
const onPath = sel && sel.kind === 'sub' ? sel.k === k : related
|
|
1628
1632
|
node.dimTarget = onPath ? 1 : (related ? 0.55 : 0.12)
|
|
1629
1633
|
}
|
|
1630
|
-
const dimMem = !!focusMain || state.pinnedOnly ||
|
|
1634
|
+
const dimMem = !!focusMain || state.pinnedOnly || searching
|
|
1631
1635
|
const onlyMem = !!(sel && sel.kind === 'mem')
|
|
1632
1636
|
for (const [id, node] of mems) {
|
|
1633
1637
|
let target = 1
|
|
1634
|
-
if (
|
|
1635
|
-
else if (state.
|
|
1638
|
+
if (searching) target = state.matches.has(id) ? 1 : 0.1
|
|
1639
|
+
else if (state.pinnedOnly && !node.mem.pinned) target = 0.15
|
|
1636
1640
|
else if (onlyMem) target = sel.id === id ? 1 : 0.55
|
|
1637
1641
|
else if (focusMain && node.folder !== focusK && !(subs.has(node.folder) && subs.get(node.folder).parentK === focusMain)) target = 0.18
|
|
1638
1642
|
node.dimTarget = dimMem || sel ? target : 1
|
|
@@ -2283,7 +2287,15 @@ async function boot() {
|
|
|
2283
2287
|
} else toast(r.error || '没删掉', 'bad')
|
|
2284
2288
|
})
|
|
2285
2289
|
}
|
|
2286
|
-
$('search').addEventListener('
|
|
2290
|
+
$('search').addEventListener('focus', () => {
|
|
2291
|
+
if (state.sel && state.sel.kind !== 'mem') {
|
|
2292
|
+
state.sel = null
|
|
2293
|
+
applyDim()
|
|
2294
|
+
renderPanel()
|
|
2295
|
+
}
|
|
2296
|
+
})
|
|
2297
|
+
|
|
2298
|
+
$('search').addEventListener('input', (e) => {
|
|
2287
2299
|
clearTimeout(searchTimer)
|
|
2288
2300
|
const v = e.target.value
|
|
2289
2301
|
searchTimer = setTimeout(() => onSearch(v), 130)
|