dsh-plugin-tlrp 0.0.0-stage → 0.3.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.
@@ -0,0 +1,77 @@
1
+ // packages/tlrp/test/memory-bridge.test.mjs
2
+ //
3
+ // 记忆桥自测:不依赖宿主、不依赖 tlmemory 的代码,只用 node:test + 真实的
4
+ // ~/.dsh/tlmemory.db(可用 TLMEMORY_DB 覆盖)。库不存在时相关用例自动 skip,
5
+ // 这样 CI/新机上依然是绿的。
6
+ //
7
+ // 运行:node --test packages/tlrp/test/memory-bridge.test.mjs
8
+
9
+ import test from 'node:test'
10
+ import assert from 'node:assert/strict'
11
+ import fs from 'node:fs'
12
+ import os from 'node:os'
13
+ import path from 'node:path'
14
+ import { createRequire } from 'node:module'
15
+
16
+ const require = createRequire(import.meta.url)
17
+ const bridge = require('../lib/memory-bridge.cjs')
18
+
19
+ const dbPath = bridge.resolveDbPath()
20
+ const dbReady = fs.existsSync(dbPath)
21
+
22
+ test('extractTerms 只产出 ≥3 字的检索锚点', () => {
23
+ const terms = bridge.extractTerms('你还记得橡木蛋糕卷吗?上次在筑梦边境的天台')
24
+ assert.ok(terms.length > 0, '应当抽出至少一个词')
25
+ for (const term of terms) assert.ok([...term].length >= 3, `词 "${term}" 少于 3 字,trigram 索引不到`)
26
+ assert.ok(terms.some((term) => term.includes('蛋糕')), `期望命中「蛋糕」,实际:${terms.join(',')}`)
27
+ })
28
+
29
+ test('extractTerms 对短句与空输入不抛错', () => {
30
+ assert.deepEqual(bridge.extractTerms(''), [])
31
+ assert.deepEqual(bridge.extractTerms('嗯'), [])
32
+ })
33
+
34
+ test('库文件不存在时降级为 no-db,且不抛错', () => {
35
+ const result = bridge.readMemoryContext({
36
+ characterId: 'firefly',
37
+ mode: 'rp',
38
+ text: '橡木蛋糕卷',
39
+ dbPath: path.join(os.tmpdir(), 'definitely-not-a-tlmemory-db.sqlite'),
40
+ })
41
+ assert.equal(result.text, '')
42
+ assert.equal(result.degraded, 'no-db')
43
+ })
44
+
45
+ test('RP 态读到 pinned 常驻羁绊(真实库)', { skip: dbReady ? false : `无 ${dbPath}` }, () => {
46
+ const result = bridge.readMemoryContext({ characterId: 'firefly', mode: 'rp', text: '' })
47
+ assert.equal(result.degraded, '', `降级码:${result.degraded}`)
48
+ assert.ok(result.pinned.length >= 1, '至少应读到 1 条 pinned 记忆')
49
+ assert.ok(
50
+ result.pinned.some((item) => item.path.startsWith('/rp/firefly/')),
51
+ `pinned 里应含 /rp/firefly/ 前缀:${result.pinned.map((i) => i.path).join(' | ')}`,
52
+ )
53
+ assert.ok(result.text.includes('tlmemory 记忆桥'))
54
+ })
55
+
56
+ test('RP 态关键词静默检索命中 lore 切片(真实库)', { skip: dbReady ? false : `无 ${dbPath}` }, () => {
57
+ const result = bridge.readMemoryContext({ characterId: 'firefly', mode: 'rp', text: '橡木蛋糕卷' })
58
+ const all = [...result.pinned, ...result.hits]
59
+ assert.ok(
60
+ all.some((item) => item.path.startsWith('/lore/firefly/')),
61
+ `应命中 lore 切片:${all.map((i) => i.path).join(' | ')}`,
62
+ )
63
+ })
64
+
65
+ test('WORK 态不会捞到 rp / lore 分区(真实库)', { skip: dbReady ? false : `无 ${dbPath}` }, () => {
66
+ const result = bridge.readMemoryContext({ characterId: 'firefly', mode: 'work', text: '橡木蛋糕卷 端口' })
67
+ for (const item of [...result.pinned, ...result.hits]) {
68
+ assert.ok(item.scope === 'work' || item.scope === 'core', `WORK 态出现了 ${item.scope} 分区:${item.path}`)
69
+ }
70
+ })
71
+
72
+ test('角色隔离:别的角色读不到 firefly 的私有 rp 记忆(真实库)', { skip: dbReady ? false : `无 ${dbPath}` }, () => {
73
+ const result = bridge.readMemoryContext({ characterId: 'sam_tactical', mode: 'rp', text: '橡木蛋糕卷' })
74
+ for (const item of [...result.pinned, ...result.hits]) {
75
+ assert.ok(item.charId === '' || item.charId === 'sam_tactical', `串戏了:${item.path} (char_id=${item.charId})`)
76
+ }
77
+ })