dsh-fish-buddy 0.8.1 → 0.8.2
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/host.js +102 -8
- package/package.json +48 -44
package/lib/host.js
CHANGED
|
@@ -16,6 +16,7 @@ import { homedir } from 'node:os'
|
|
|
16
16
|
import { join, dirname } from 'node:path'
|
|
17
17
|
import { fileURLToPath } from 'node:url'
|
|
18
18
|
import { randomUUID } from 'node:crypto'
|
|
19
|
+
import * as zlib from 'node:zlib'
|
|
19
20
|
|
|
20
21
|
export const name = 'fish-buddy'
|
|
21
22
|
|
|
@@ -304,20 +305,113 @@ export function apply(ctx, inlineConfig) {
|
|
|
304
305
|
|
|
305
306
|
// ---------- 会话清单(设置页的下拉用) ----------
|
|
306
307
|
const 会话清单 = () => {
|
|
308
|
+
// ⚠ 2026-11-03:原来只列「活着的会话」(sessions.list) —— 窗口一关就选不到了,
|
|
309
|
+
// 未分组那批更是永远选不到。改成扫磁盘,跨所有工作区,按同一套规矩过滤。
|
|
307
310
|
const 出 = []
|
|
308
311
|
try {
|
|
309
|
-
const
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
312
|
+
const 根 = join(目录, 'sessions')
|
|
313
|
+
const 缓存 = join(目录, 'storages', 'session_projcache', 'sessions')
|
|
314
|
+
const 归档 = new Set()
|
|
315
|
+
try {
|
|
316
|
+
const wr = 取服务('workspaceRegistry')
|
|
317
|
+
const ids = wr && wr.archivedSessionIds
|
|
318
|
+
if (Array.isArray(ids)) for (const x of ids) 归档.add(String(x))
|
|
319
|
+
} catch (error) {}
|
|
320
|
+
try {
|
|
321
|
+
const w = JSON.parse(readFileSync(join(目录, 'storages', 'workspace.json'), 'utf8'))
|
|
322
|
+
for (const x of (w && w.global && w.global.archivedSessionIds) || []) 归档.add(String(x))
|
|
323
|
+
} catch (error) {}
|
|
324
|
+
|
|
325
|
+
let 一层们 = []
|
|
326
|
+
try {
|
|
327
|
+
一层们 = readdirSync(根, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name)
|
|
328
|
+
} catch (error) {
|
|
329
|
+
return 出
|
|
330
|
+
}
|
|
331
|
+
const 位置 = []
|
|
332
|
+
for (const 一层 of 一层们) {
|
|
333
|
+
if (existsSync(join(根, 一层, 'session.v4.jsonl.zstd'))) {
|
|
334
|
+
位置.push({ ws: '', sid: 一层 })
|
|
335
|
+
continue
|
|
336
|
+
}
|
|
337
|
+
let 子们 = []
|
|
338
|
+
try {
|
|
339
|
+
子们 = readdirSync(join(根, 一层), { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name)
|
|
340
|
+
} catch (error) {
|
|
341
|
+
continue
|
|
342
|
+
}
|
|
343
|
+
for (const sid of 子们) 位置.push({ ws: 一层, sid })
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const 行们 = []
|
|
347
|
+
for (const { ws, sid } of 位置) {
|
|
348
|
+
const 日志 = join(根, ws, sid, 'session.v4.jsonl.zstd')
|
|
349
|
+
if (!existsSync(日志)) continue
|
|
350
|
+
if (归档.has(sid)) continue
|
|
351
|
+
let 大小 = 0
|
|
352
|
+
try {
|
|
353
|
+
大小 = statSync(日志).size
|
|
354
|
+
} catch (error) {}
|
|
355
|
+
if (大小 < 1024) continue // 空会话
|
|
356
|
+
let 标题 = ''
|
|
357
|
+
let 空 = false
|
|
358
|
+
let 子代理 = false
|
|
359
|
+
let 时 = 0
|
|
360
|
+
try {
|
|
361
|
+
const r = JSON.parse(readFileSync(join(缓存, sid + '.json'), 'utf8'))?.record?.rows || {}
|
|
362
|
+
标题 = String((r.title && r.title.val) || '')
|
|
363
|
+
const meta = (r.sessionListMetadata && r.sessionListMetadata.val) || {}
|
|
364
|
+
时 = Number(meta.lastPromptAt || 0)
|
|
365
|
+
空 = Boolean(meta.blank)
|
|
366
|
+
子代理 = Boolean(r.subagent && r.subagent.val && r.subagent.val.identity)
|
|
367
|
+
} catch (error) {}
|
|
368
|
+
if (空) continue
|
|
369
|
+
if (!标题 || 子代理) {
|
|
370
|
+
// 没缓存或缓存没说清楚 → 看日志头:子代理/深度>0 直接排除,顺便捞第一句话当标题
|
|
314
371
|
try {
|
|
315
|
-
const
|
|
316
|
-
|
|
372
|
+
const 缓 = readFileSync(日志).subarray(0, 524288)
|
|
373
|
+
const 帧们 = []
|
|
374
|
+
for (let i = 0; i + 4 <= 缓.length; i++) {
|
|
375
|
+
if (缓[i] === 0x28 && 缓[i + 1] === 0xb5 && 缓[i + 2] === 0x2f && 缓[i + 3] === 0xfd) 帧们.push(i)
|
|
376
|
+
}
|
|
377
|
+
for (let k = 0; k < Math.min(帧们.length, 64); k++) {
|
|
378
|
+
const 段 = 缓.subarray(帧们[k], k + 1 < 帧们.length ? 帧们[k + 1] : 缓.length)
|
|
379
|
+
let 文 = ''
|
|
380
|
+
try {
|
|
381
|
+
文 = zlib.zstdDecompressSync(段).toString('utf8')
|
|
382
|
+
} catch (error) {
|
|
383
|
+
continue
|
|
384
|
+
}
|
|
385
|
+
for (const 行 of 文.split(String.fromCharCode(10))) {
|
|
386
|
+
if (!行.trim()) continue
|
|
387
|
+
let e
|
|
388
|
+
try {
|
|
389
|
+
e = JSON.parse(行)
|
|
390
|
+
} catch (error) {
|
|
391
|
+
continue
|
|
392
|
+
}
|
|
393
|
+
if (e.type === 'session') {
|
|
394
|
+
if (e.origin === 'subagent' || Number(e.delegationDepth || 0) > 0) 子代理 = true
|
|
395
|
+
if (!时) 时 = Number(e.createdAt || 0)
|
|
396
|
+
continue
|
|
397
|
+
}
|
|
398
|
+
if (标题) continue
|
|
399
|
+
if (e.type !== 'user/message') continue
|
|
400
|
+
const 源 = (e.data && e.data.source && e.data.source.kind) || ''
|
|
401
|
+
if (源 !== 'user') continue
|
|
402
|
+
const c = e.data && e.data.content
|
|
403
|
+
const t = (Array.isArray(c) ? c : []).filter((x) => x && x.type === 'text').map((x) => x.text).join(' ').trim()
|
|
404
|
+
if (t) 标题 = t.slice(0, 40)
|
|
405
|
+
}
|
|
406
|
+
if (子代理 && 标题) break
|
|
407
|
+
}
|
|
317
408
|
} catch (error) {}
|
|
318
|
-
出.push({ id: String(s.id), 标题 })
|
|
319
409
|
}
|
|
410
|
+
if (子代理) continue
|
|
411
|
+
行们.push({ id: sid, 标题: 标题 || ('未命名会话 · ' + (时 ? new Date(时).toLocaleDateString('zh-CN') : sid.slice(0, 8))), at: 时 })
|
|
320
412
|
}
|
|
413
|
+
行们.sort((a, b) => b.at - a.at)
|
|
414
|
+
for (const r of 行们) 出.push({ id: r.id, 标题: r.标题 })
|
|
321
415
|
} catch (error) {
|
|
322
416
|
记账('列会话出错:' + 说(error))
|
|
323
417
|
}
|
package/package.json
CHANGED
|
@@ -1,44 +1,48 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dsh-fish-buddy",
|
|
3
|
-
"version": "0.8.
|
|
4
|
-
"description": "鱼搭子 · DSH 这半边:桌面小挂件说的话送进你绑定的会话,她的回话再递回挂件。挂件是独立程序,这里只负责接线。",
|
|
5
|
-
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"keywords": [
|
|
8
|
-
"deepseek-harness",
|
|
9
|
-
"dsh-plugin",
|
|
10
|
-
"companion",
|
|
11
|
-
"voice",
|
|
12
|
-
"call"
|
|
13
|
-
],
|
|
14
|
-
"main": "lib/host.js",
|
|
15
|
-
"exports": {
|
|
16
|
-
".": "./lib/host.js",
|
|
17
|
-
"./client": "./lib/client.js",
|
|
18
|
-
"./package.json": "./package.json",
|
|
19
|
-
"./locale/*.json": "./locale/*.json",
|
|
20
|
-
"./icon": "./icon.png"
|
|
21
|
-
},
|
|
22
|
-
"icon": "./icon.png",
|
|
23
|
-
"files": [
|
|
24
|
-
"lib",
|
|
25
|
-
"locale",
|
|
26
|
-
"icon.png",
|
|
27
|
-
"cordis.patch.yml",
|
|
28
|
-
"README.md"
|
|
29
|
-
],
|
|
30
|
-
"dsh": {
|
|
31
|
-
"bundle": {
|
|
32
|
-
"patch": "./cordis.patch.yml"
|
|
33
|
-
},
|
|
34
|
-
"client": {
|
|
35
|
-
"platform": "web",
|
|
36
|
-
"inject": [
|
|
37
|
-
"slots"
|
|
38
|
-
],
|
|
39
|
-
"external": [
|
|
40
|
-
"react"
|
|
41
|
-
]
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-fish-buddy",
|
|
3
|
+
"version": "0.8.2",
|
|
4
|
+
"description": "鱼搭子 · DSH 这半边:桌面小挂件说的话送进你绑定的会话,她的回话再递回挂件。挂件是独立程序,这里只负责接线。",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"deepseek-harness",
|
|
9
|
+
"dsh-plugin",
|
|
10
|
+
"companion",
|
|
11
|
+
"voice",
|
|
12
|
+
"call"
|
|
13
|
+
],
|
|
14
|
+
"main": "lib/host.js",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": "./lib/host.js",
|
|
17
|
+
"./client": "./lib/client.js",
|
|
18
|
+
"./package.json": "./package.json",
|
|
19
|
+
"./locale/*.json": "./locale/*.json",
|
|
20
|
+
"./icon": "./icon.png"
|
|
21
|
+
},
|
|
22
|
+
"icon": "./icon.png",
|
|
23
|
+
"files": [
|
|
24
|
+
"lib",
|
|
25
|
+
"locale",
|
|
26
|
+
"icon.png",
|
|
27
|
+
"cordis.patch.yml",
|
|
28
|
+
"README.md"
|
|
29
|
+
],
|
|
30
|
+
"dsh": {
|
|
31
|
+
"bundle": {
|
|
32
|
+
"patch": "./cordis.patch.yml"
|
|
33
|
+
},
|
|
34
|
+
"client": {
|
|
35
|
+
"platform": "web",
|
|
36
|
+
"inject": [
|
|
37
|
+
"slots"
|
|
38
|
+
],
|
|
39
|
+
"external": [
|
|
40
|
+
"react"
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=22",
|
|
46
|
+
"dsh": ">=0.2.1-rc.2"
|
|
47
|
+
}
|
|
48
|
+
}
|