dsh-fish-memory 0.0.0-stage → 1.4.4
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/LICENSE +21 -0
- package/README.md +285 -2
- package/cordis.patch.yml +3 -0
- package/lib/atomic-file.mjs +32 -0
- package/lib/client.js +4043 -0
- package/lib/hostdeps.mjs +157 -0
- package/lib/index.js +6622 -0
- package/lib/selfupdate.mjs +151 -0
- package/lib/store-merge.mjs +31 -0
- package/lib//347/224/237/346/210/220/346/241/243/346/241/210.js +573 -0
- package/lib//350/257/215/345/205/270-/346/235/245/346/272/220.txt +53 -0
- package/lib//350/257/215/345/205/270.txt +109750 -0
- package/lib//350/257/215/351/242/221.txt +20000 -0
- package/package.json +56 -6
package/lib/hostdeps.mjs
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* lib/hostdeps.mjs —— 从宿主那棵树里取 `@deepseek-ai/*`(拿不到就退到"自己的依赖")
|
|
3
|
+
* ============================================================================
|
|
4
|
+
* 🔴 为什么要有它(2026-10-16 一位用户递来的完整报告,本机也复现了):
|
|
5
|
+
* `index.js` 顶部裸 import `@deepseek-ai/schemastery` 和 `@deepseek-ai/dsh-tools`,
|
|
6
|
+
* 而它们在 package.json 里是 **optional peer** ⇒ 桌面版 profile(`autoInstallPeers: false`)
|
|
7
|
+
* **永远不装它们** ⇒ 插件整条不激活,DSH 只留一句
|
|
8
|
+
* `warning: 1 entry did not activate … failed to import` ✓
|
|
9
|
+
* (web profile 上之所以一直没事,是因为 profile 树里恰好有别的插件把它们 hoist 上来了 —— 这是运气 ✗)
|
|
10
|
+
* ⚠️ `dsh-tools` 自己还有 7 个顶层 import、其中 4 个是 peer ⇒ 光把它装上也救不回来 ✗。
|
|
11
|
+
*
|
|
12
|
+
* ⭐ 策略(两条一起走):
|
|
13
|
+
* ① **优先从宿主那棵树里解析**(跟宿主用同一份,行为最一致);
|
|
14
|
+
* ② 解析不到就 **bare import**(靠我们自己 package.json 的 `dependencies` 装一份保底);
|
|
15
|
+
* ③ `schemastery` 彻底拿不到 ⇒ 返回 null,**插件照常加载**(只是没有 Config、设置页降级)——
|
|
16
|
+
* **绝不因为一个 import 就让整条插件不激活** ✗✓。
|
|
17
|
+
* ============================================================================
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs'
|
|
20
|
+
import { join, dirname } from 'node:path'
|
|
21
|
+
import { homedir } from 'node:os'
|
|
22
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
23
|
+
import { randomUUID } from 'node:crypto'
|
|
24
|
+
|
|
25
|
+
/** 插件自己那棵树(`dependencies` 装出来的那份)—— 用模块位置算,别依赖 cwd */
|
|
26
|
+
const SELF_MODULES = join(dirname(fileURLToPath(import.meta.url)), '..', 'node_modules', '@deepseek-ai')
|
|
27
|
+
|
|
28
|
+
/** 可能藏着宿主 `@deepseek-ai` 包的地方(不写死某一台机器,按可能性排序) */
|
|
29
|
+
export function candidateRoots() {
|
|
30
|
+
const out = []
|
|
31
|
+
const push = (p) => { if (p && !out.includes(p)) out.push(p) }
|
|
32
|
+
push(process.env.DSH_HOST_MODULES)
|
|
33
|
+
|
|
34
|
+
const appdata = process.env.APPDATA
|
|
35
|
+
if (appdata) {
|
|
36
|
+
const npm = join(appdata, 'npm', 'node_modules')
|
|
37
|
+
push(join(npm, '@deepseek-ai', 'dsh', 'node_modules', '@deepseek-ai'))
|
|
38
|
+
push(join(npm, '@deepseek-ai'))
|
|
39
|
+
// 桌面版可能叫别的包名(dsh-desktop / dsh-next…)⇒ 逐个看它们的 node_modules
|
|
40
|
+
try {
|
|
41
|
+
for (const n of readdirSync(join(npm, '@deepseek-ai'))) {
|
|
42
|
+
push(join(npm, '@deepseek-ai', n, 'node_modules', '@deepseek-ai'))
|
|
43
|
+
}
|
|
44
|
+
} catch { /* 没有就算了 */ }
|
|
45
|
+
}
|
|
46
|
+
push('/usr/local/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai')
|
|
47
|
+
push('/usr/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai')
|
|
48
|
+
push('/usr/local/lib/node_modules/@deepseek-ai')
|
|
49
|
+
push('/usr/lib/node_modules/@deepseek-ai')
|
|
50
|
+
|
|
51
|
+
// profile 树:有些机器上这些包是被别的插件 hoist 到 profile 根上的
|
|
52
|
+
try {
|
|
53
|
+
const dshHome = process.env.DSH_HOME || join(homedir(), '.dsh')
|
|
54
|
+
for (const p of readdirSync(join(dshHome, 'profiles'))) {
|
|
55
|
+
push(join(dshHome, 'profiles', p, 'node_modules', '@deepseek-ai'))
|
|
56
|
+
}
|
|
57
|
+
} catch { /* 没有就算了 */ }
|
|
58
|
+
|
|
59
|
+
// 插件自己那份(package.json 的 dependencies 装出来的)—— 放最后,前面优先"跟宿主同一份"
|
|
60
|
+
push(SELF_MODULES)
|
|
61
|
+
return out
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** 按包的 exports['.'] 找入口文件,返回 file:// URL */
|
|
65
|
+
function entryUrlFor(root, name) {
|
|
66
|
+
try {
|
|
67
|
+
const dir = join(root, name)
|
|
68
|
+
const pkgFile = join(dir, 'package.json')
|
|
69
|
+
if (!existsSync(pkgFile)) return null
|
|
70
|
+
const pkg = JSON.parse(readFileSync(pkgFile, 'utf8'))
|
|
71
|
+
const dot = pkg.exports?.['.']
|
|
72
|
+
const rel = typeof dot === 'string'
|
|
73
|
+
? dot
|
|
74
|
+
: (dot?.import || dot?.default || pkg.module || pkg.main)
|
|
75
|
+
if (!rel) return null
|
|
76
|
+
const file = join(dir, String(rel).replace(/^\.\//, ''))
|
|
77
|
+
return existsSync(file) ? pathToFileURL(file).href : null
|
|
78
|
+
} catch { return null }
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** 试从宿主树里 import 一个包;拿不到返回 null(失败原因写进 notes,方便远程排查) */
|
|
82
|
+
async function fromHostTree(name, log) {
|
|
83
|
+
const fails = []
|
|
84
|
+
for (const root of candidateRoots()) {
|
|
85
|
+
if (root === SELF_MODULES) continue // 自己那份交给下面的 bare import 处理
|
|
86
|
+
const url = entryUrlFor(root, name)
|
|
87
|
+
if (!url) continue
|
|
88
|
+
try {
|
|
89
|
+
const mod = await import(url)
|
|
90
|
+
log(`${name}:从宿主树取到(${url.replace(/^file:\/\/\//, '')})`)
|
|
91
|
+
return mod
|
|
92
|
+
} catch (e) { fails.push(`${e?.code || 'ERR'}:${root}`) }
|
|
93
|
+
}
|
|
94
|
+
if (fails.length) log(`${name}:宿主树里都不行(${fails.slice(0, 3).join(' ')})`)
|
|
95
|
+
return null
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** 兜底:这是**我们自己的等价实现**,只在拿不到宿主的 dsh-tools 时用 */
|
|
99
|
+
function localDefineTool(options, log) {
|
|
100
|
+
// 宿主的 defineTool 会做 spec→JSONSchema 转换 + 参数校验;我们的 parameters / output.schema
|
|
101
|
+
// **本来就是标准 JSON Schema**(2026-10-14 那次 additionalProperties 报错就是被它校验出来的),
|
|
102
|
+
// 所以这里只补一条同样的校验,别的原样返回。
|
|
103
|
+
const check = (schema, where) => {
|
|
104
|
+
if (!schema || typeof schema !== 'object') return
|
|
105
|
+
if (schema.type === 'object' && schema.additionalProperties === undefined) {
|
|
106
|
+
throw new Error(`defineTool(${options.name}): ${where} 是 object 却没写 additionalProperties`)
|
|
107
|
+
}
|
|
108
|
+
for (const [k, v] of Object.entries(schema.properties || {})) check(v, `${where}.properties.${k}`)
|
|
109
|
+
}
|
|
110
|
+
check(options.parameters, 'parameters')
|
|
111
|
+
check(options.output?.schema, 'output.schema')
|
|
112
|
+
log?.(`dsh-tools 拿不到 —— 用本地等价实现顶上了(工具 ${options.name})`)
|
|
113
|
+
return options
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* 取回宿主半端要用的一点点东西
|
|
118
|
+
* @returns {Promise<{z:any, defineTool:Function|null, notes:string[]}>}
|
|
119
|
+
*/
|
|
120
|
+
export async function loadHostDeps() {
|
|
121
|
+
const notes = []
|
|
122
|
+
const log = (m) => notes.push(m)
|
|
123
|
+
|
|
124
|
+
// ① schemastery(Config 要用;宿主设置层要用**它自己那份**读 volatile 字段)
|
|
125
|
+
let zMod = await fromHostTree('schemastery', log)
|
|
126
|
+
if (!zMod) {
|
|
127
|
+
try { zMod = await import('@deepseek-ai/schemastery'); log('schemastery:宿主树里没有,用自己依赖里那份') }
|
|
128
|
+
catch (e) { log(`⚠️ schemastery 彻底拿不到(${e?.code || ''} ${String(e?.message || '').slice(0, 120)})—— 这一份插件没有 Config,设置页会降级(插件本体照常跑)`) }
|
|
129
|
+
}
|
|
130
|
+
const z = zMod?.default ?? zMod ?? null
|
|
131
|
+
|
|
132
|
+
// ② dsh-tools 的 defineTool(拿不到就用本地等价实现 —— 这是本次桌面版修复的关键一步)
|
|
133
|
+
let defineTool = null
|
|
134
|
+
let dtMod = await fromHostTree('dsh-tools', log)
|
|
135
|
+
if (!dtMod) {
|
|
136
|
+
try { dtMod = await import('@deepseek-ai/dsh-tools'); log('dsh-tools:宿主树里没有,用自己依赖里那份') }
|
|
137
|
+
catch (e) { log(`dsh-tools 拿不到(${e?.code || ''})—— 用本地等价实现顶上`); dtMod = null }
|
|
138
|
+
}
|
|
139
|
+
defineTool = dtMod?.defineTool || ((options) => localDefineTool(options, log))
|
|
140
|
+
|
|
141
|
+
// ③ dsh-llm 的 createUserMessage(2026-10-20 补:原来这一条是裸 import,
|
|
142
|
+
// 在没装它的机器上会让整条插件不激活 ⇒ DSH 把 bundle 条目直接摘掉、页面 404)
|
|
143
|
+
let createUserMessage = null
|
|
144
|
+
let llmMod = await fromHostTree('dsh-llm', log)
|
|
145
|
+
if (!llmMod) {
|
|
146
|
+
try { llmMod = await import('@deepseek-ai/dsh-llm'); log('dsh-llm:宿主树里没有,用自己依赖里那份') }
|
|
147
|
+
catch (e) { log(`dsh-llm 拿不到(${e?.code || ''})—— 用本地等价实现顶上`); llmMod = null }
|
|
148
|
+
}
|
|
149
|
+
createUserMessage = llmMod?.createUserMessage || ((payload) => {
|
|
150
|
+
const p = payload && typeof payload === 'object' ? payload : {}
|
|
151
|
+
const msg = { id: randomUUID(), role: 'user', content: Array.isArray(p.content) ? p.content : [] }
|
|
152
|
+
if (p.source !== undefined) msg.source = p.source
|
|
153
|
+
return msg
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
return { z, defineTool, createUserMessage, notes }
|
|
157
|
+
}
|