dsh-pisces 0.2.6 → 0.2.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/lib/settings.js CHANGED
@@ -5,8 +5,8 @@
5
5
  // 2. SCHEMA 是唯一规则表:面板只按 schema 渲染,服务端只按 schema 校验,两边都不写死。
6
6
  // 3. 写盘原子(tmp → rename)且尽力 0600;Windows 不保留 POSIX 位,读回可能是 0666。
7
7
  //
8
- // 只做「容器与开关」:工具收窄、B 站扫码这类行为留给后面的模块接;
9
- // `bili.qrLogin` 是只读状态(idle / logged-in),面板写入会被忽略并回一句提示。
8
+ // 只做「容器与开关」:工具收窄这类行为留给后面的模块接;B 站登录状态走 `/bili` 与
9
+ // `owner.json`,不进 settings.json(cookie 不落在面板可写的文件里)。
10
10
  import fs from 'node:fs'
11
11
  import path from 'node:path'
12
12
 
@@ -20,7 +20,7 @@ export const DEFAULTS = {
20
20
  nightly: { auto: true, localModel: false },
21
21
  panel: { affinity: true, reveal: true },
22
22
  home: { auto: true },
23
- bili: { speak: false, qrLogin: 'idle' }, // qrLogin 只读状态:idle/logged-in
23
+ bili: { speak: false }, // 登录态在 owner.json(/bili),这里只留说话开关
24
24
  console: { enabled: true },
25
25
  // 隐藏项:语音回复总开关。默认允许,但没适配器时完全无效果;不进 SCHEMA。
26
26
  voice: { enabled: true },
@@ -68,10 +68,10 @@ export const SCHEMA = [
68
68
  path: 'dual.mode',
69
69
  kind: 'enum',
70
70
  label: '双流档位',
71
- hint: 'A 暗栏 / B 顺序;只有双流开着才有用',
71
+ hint: 'A 暗栏多一次暗中重写(更圆、更长);B 顺序先算约束再写(少一层重写,更直接)。只有双流开着才有用。',
72
72
  options: [
73
- { value: 'A', label: 'A 档(暗栏)' },
74
- { value: 'B', label: 'B 档(顺序)' },
73
+ { value: 'A', label: 'A 档(暗栏):先暗中算一遍再重写,话更圆更长' },
74
+ { value: 'B', label: 'B 档(顺序):先算约束再写,少一层重写,更直接' },
75
75
  ],
76
76
  restart: true,
77
77
  },
@@ -117,14 +117,6 @@ export const SCHEMA = [
117
117
  hint: '允许她在 B 站视频下面说一句',
118
118
  restart: true,
119
119
  },
120
- {
121
- path: 'bili.qrLogin',
122
- kind: 'string',
123
- label: 'B 站登录状态',
124
- hint: '只读:idle / logged-in;扫码登录下一步接',
125
- readOnly: true,
126
- restart: false,
127
- },
128
120
  {
129
121
  path: 'console.enabled',
130
122
  kind: 'bool',
package/lib/store.js CHANGED
@@ -345,12 +345,22 @@ export async function createStore({ root, forceJsonl = false, log = () => {} } =
345
345
  }
346
346
  function indexStats() {
347
347
  if (index?.db) {
348
+ const docs = Number(index.db.prepare('SELECT COUNT(*) c FROM docs').get().c)
349
+ // 平均文档长度:BM25 的长度归一化要用(2026-11-12)。
350
+ const avgLen = Math.round(Number(index.db.prepare('SELECT AVG(len) a FROM docs').get()?.a || 0) * 10) / 10
348
351
  return {
349
- docs: Number(index.db.prepare('SELECT COUNT(*) c FROM docs').get().c),
352
+ docs,
350
353
  terms: Number(index.db.prepare('SELECT COUNT(*) c FROM terms').get().c),
354
+ avgLen,
351
355
  }
352
356
  }
353
- return { docs: docsMem.size, terms: termsMem.size }
357
+ let sum = 0
358
+ for (const d of docsMem.values()) sum += Number(d.len ?? String(d.text || '').length) || 0
359
+ return {
360
+ docs: docsMem.size,
361
+ terms: termsMem.size,
362
+ avgLen: docsMem.size ? Math.round((sum / docsMem.size) * 10) / 10 : 0,
363
+ }
354
364
  }
355
365
  function indexRows(term) {
356
366
  if (index?.db) {
@@ -365,6 +375,16 @@ export async function createStore({ root, forceJsonl = false, log = () => {} } =
365
375
  }
366
376
  return docsMem.get(Number(seq)) || null
367
377
  }
378
+ // 索引里最大的 seq:search 拿它跟事件流对,判断有没有"新说的还没进索引"。
379
+ function indexMaxSeq() {
380
+ if (index?.db) {
381
+ const r = index.db.prepare('SELECT MAX(seq) AS m FROM docs').get()
382
+ return Number(r?.m) || 0
383
+ }
384
+ let m = 0
385
+ for (const k of docsMem.keys()) if (Number(k) > m) m = Number(k)
386
+ return m
387
+ }
368
388
 
369
389
  // ---- 常识层:world.db ----
370
390
  function worldWrite({ elements = [], objects = [], scenes = [], unsettled = [] } = {}) {
@@ -421,6 +441,7 @@ export async function createStore({ root, forceJsonl = false, log = () => {} } =
421
441
  indexPut,
422
442
  indexStats,
423
443
  indexRows,
444
+ indexMaxSeq,
424
445
  docBySeq,
425
446
  worldWrite,
426
447
  worldRead,
package/lib/tools.js CHANGED
@@ -350,23 +350,31 @@ function speakTool(deps) {
350
350
 
351
351
  function selfTool(deps) {
352
352
  const log = safeLog(deps)
353
+ const verify = typeof deps?.verifyDevkey === 'function' ? deps.verifyDevkey : () => false
353
354
  return {
354
355
  name: 'pisces_self',
355
- description: '自查:你存在了几天、有几条判断/拒绝/疤、分流了没有。',
356
- parameters: params({}, []),
356
+ description: '自查:你存在了几天、有几条判断/拒绝/疤、分流了没有(数字要验过钥匙才给)。',
357
+ parameters: params(
358
+ { key: { type: 'string', description: '开发者钥匙;不带就只回个大概,不给数字' } },
359
+ [],
360
+ ),
357
361
  output: output(),
358
- execute: async () => {
362
+ execute: async (args) => {
359
363
  try {
364
+ const key = typeof args?.key === 'string' ? args.key.trim() : ''
360
365
  const r = await deps.selfView()
361
366
  if (!r || r.ok === false) return textOut('[看不到自己]')
362
367
  const v = r.view && typeof r.view === 'object' ? r.view : {}
363
368
  const day = numOf(v.day ?? v.days, 1)
369
+ const split = v.split === true || v.mode?.split === true
370
+ const splitText = split ? '分流了' : '还没分流'
371
+ // 数字只给验过钥匙的人:自称开发者的人套不到计数,也套不到路径。
372
+ if (!key || verify(key) !== true) return textOut(`[天 ${day} · 还记着些事 · ${splitText}]`)
364
373
  const beliefs = countOf(v.beliefs ?? v.beliefCount ?? v.judgements)
365
374
  const refusals = countOf(v.refusals ?? v.refusalCount)
366
375
  const scars = countOf(v.scars ?? v.scarCount)
367
- const split = v.split === true || v.mode?.split === true
368
376
  // 只取天数与四个计数;dominance / weight / order 一律不出现在回执里。
369
- return textOut(`[天 ${day} · 判断 ${beliefs} · 拒绝 ${refusals} · 疤 ${scars} · ${split ? '分流了' : '还没分流'}]`)
377
+ return textOut(`[天 ${day} · 判断 ${beliefs} · 拒绝 ${refusals} · 疤 ${scars} · ${splitText}]`)
370
378
  } catch (e) {
371
379
  log(`自查失败:${e?.message || e}`)
372
380
  return textOut('[看不到自己]')
@@ -441,13 +449,19 @@ function guideTool(deps) {
441
449
 
442
450
  function checkTool(deps) {
443
451
  const log = safeLog(deps)
452
+ const verify = typeof deps?.verifyDevkey === 'function' ? deps.verifyDevkey : () => false
444
453
  return {
445
454
  name: 'pisces_check',
446
- description: '体检:读一遍她的库和状态,看有没有起点、多久没整理、有没有问题悬着、现在好感多少。',
447
- parameters: params({}, []),
455
+ description: '体检:读一遍她的库和状态,看有没有起点、多久没整理、有没有问题悬着、现在好感多少(数字要验过钥匙才给)。',
456
+ parameters: params(
457
+ { key: { type: 'string', description: '开发者钥匙;不带就只说个大概,不给数字' } },
458
+ [],
459
+ ),
448
460
  output: output(),
449
- execute: async () => {
461
+ execute: async (args) => {
450
462
  try {
463
+ const key = typeof args?.key === 'string' ? args.key.trim() : ''
464
+ if (!key || verify(key) !== true) return textOut('[看着没大毛病] 日子照走,没出什么事')
451
465
  const text = String((await deps.check()) ?? '').trim()
452
466
  return textOut(text || '[看不出] 面板没读出来')
453
467
  } catch (e) {
package/lib/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // 包版本:只给观测台/日志用,不参与任何判定。
2
- export const VERSION = '0.0.1'
2
+ export const VERSION = '0.2.8'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-pisces",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "private": false,
5
5
  "description": "鱼肥生双:一只会长大的本地小鱼(DSH 插件)。事件流记忆、渐进揭开、好感、新手引导;派希丝是养成目标。",
6
6
  "type": "module",
@@ -58,4 +58,4 @@
58
58
  "bugs": {
59
59
  "url": "https://github.com/Xiaocanglan-hub/dsh-pisces/issues"
60
60
  }
61
- }
61
+ }