dsh-vscode-mode 0.1.42 → 0.1.44
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/client.js +107 -66
- package/lib/client.js.map +1 -1
- package/lib/index.js +252 -26
- package/lib/index.js.map +1 -1
- package/package.json +1 -5
- package/src/client/monaco/lsp/providers.ts +129 -62
- package/src/client/styles/editor.css +0 -6
- package/src/client/ui/McpSettings.ts +5 -1
- package/src/compat.ts +46 -5
- package/src/dshVersion.ts +121 -0
- package/src/fileOpenSettings.ts +143 -24
- package/src/host-deps.d.ts +5 -5
- package/src/index.ts +2 -1
- package/src/lsp/settings.ts +12 -6
- package/src/shared/compat.ts +9 -3
package/src/fileOpenSettings.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dsh-vscode-mode host — 文件链接打开工具 + 快捷键的持久化设置。
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* 依赖守卫:schemastery 动态加载;@deepseek-ai/dsh-settings 仅作 legacy 探测——
|
|
4
|
+
* rc 线导出 installSettingsSection free function,0.1.2-alpha 起移除(改由 settings
|
|
5
|
+
* 服务的 installSection 方法承载,见 runSettingsInstall 三策略)。
|
|
6
|
+
* 缺失/任一策略失败时插件仍可加载(fileOpenTool 降级为配置值,compat 报告可见),
|
|
7
|
+
* 全程 try/catch,不产生未捕获 rejection。
|
|
8
|
+
* 作者 ddj 2026年08月24号 / 2026年08月26号 / 2026年09月02号
|
|
6
9
|
*/
|
|
7
10
|
import type { Ctx } from './store.js'
|
|
8
11
|
import { KEYBINDING_DEFAULTS } from './shared/keybindings.js'
|
|
@@ -20,7 +23,7 @@ type SettingsProvider = {
|
|
|
20
23
|
|
|
21
24
|
/** 动态依赖的装载结果(宽松类型:dsh-settings 无本地类型声明)。 */
|
|
22
25
|
export interface SettingsDeps {
|
|
23
|
-
installSettingsSection
|
|
26
|
+
installSettingsSection?: (ctx: Ctx, ns: string, schema: unknown, entry: object, hooks: object) => void
|
|
24
27
|
z: {
|
|
25
28
|
object: (shape: Record<string, unknown>) => { default: (value: Record<string, unknown>) => unknown }
|
|
26
29
|
string: () => { default: (value: string) => unknown }
|
|
@@ -33,19 +36,9 @@ export type SettingsDepsLoader = () => Promise<SettingsDeps | null>
|
|
|
33
36
|
let depsPromise: Promise<SettingsDeps | null> | undefined
|
|
34
37
|
|
|
35
38
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* @returns keybindings 字段形状
|
|
40
|
-
*/
|
|
41
|
-
function keybindingsShape(z: SettingsDeps['z']): Record<string, unknown> {
|
|
42
|
-
const shape: Record<string, unknown> = {}
|
|
43
|
-
for (const [id, chord] of Object.entries(KEYBINDING_DEFAULTS)) shape[id] = z.string().default(chord)
|
|
44
|
-
return shape
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* 动态加载设置依赖(模块级缓存;任一缺失返回 null 而非抛错)。
|
|
39
|
+
* 动态加载设置依赖(模块级缓存;任一缺失/失败返回 null 而非抛错)。
|
|
40
|
+
* installSettingsSection 仅在 rc 线 dsh-settings 中存在时提供(alpha 起移除,
|
|
41
|
+
* 属性探测得到 undefined,不抛错)。
|
|
49
42
|
* @author ddj 2026年08月24号
|
|
50
43
|
* @returns 设置依赖或 null
|
|
51
44
|
*/
|
|
@@ -53,14 +46,132 @@ export function loadSettingsDeps(): Promise<SettingsDeps | null> {
|
|
|
53
46
|
if (!depsPromise) {
|
|
54
47
|
depsPromise = Promise.all([import('@deepseek-ai/dsh-settings'), import('schemastery')])
|
|
55
48
|
.then(([dshSettings, schemastery]) => ({
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
// dsh-settings 类型声明随版本变化(rc.8 有 d.ts、alpha 已移除导出),统一经 unknown 松绑
|
|
50
|
+
installSettingsSection: (dshSettings as unknown as { installSettingsSection?: SettingsDeps['installSettingsSection'] }).installSettingsSection,
|
|
51
|
+
z: (schemastery as unknown as { default: SettingsDeps['z'] }).default,
|
|
58
52
|
}))
|
|
59
53
|
.catch(() => null)
|
|
60
54
|
}
|
|
61
55
|
return depsPromise
|
|
62
56
|
}
|
|
63
57
|
|
|
58
|
+
/** 设置 section 安装策略(版本适配机制的观测值)。 */
|
|
59
|
+
export type SettingsInstallStrategy = 'legacy' | 'service' | 'none' | 'unknown'
|
|
60
|
+
|
|
61
|
+
const INSTALL_UNMOUNTED = '设置 section 尚未装配'
|
|
62
|
+
const INSTALL_LEGACY = 'rc 线:dsh-settings.installSettingsSection'
|
|
63
|
+
const INSTALL_SERVICE = '0.1.2-alpha 线:settings 服务 installSection'
|
|
64
|
+
const INSTALL_NONE = '两路均不可用:设置持久化降级为配置值'
|
|
65
|
+
|
|
66
|
+
interface ObservedInstall { strategy: SettingsInstallStrategy; note: string }
|
|
67
|
+
let observedInstall: ObservedInstall = { strategy: 'unknown', note: INSTALL_UNMOUNTED }
|
|
68
|
+
|
|
69
|
+
/** 记录最近一次安装策略(供兼容报告展示;失败路径也记录,便于诊断)。 */
|
|
70
|
+
function recordInstall(strategy: SettingsInstallStrategy, note: string): SettingsInstallStrategy {
|
|
71
|
+
observedInstall = { strategy, note }
|
|
72
|
+
return strategy
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** 读取观测到的安装策略(供报告;测试可用 reset 复位)。 */
|
|
76
|
+
export function settingsInstallStrategy(): SettingsInstallStrategy {
|
|
77
|
+
return observedInstall.strategy
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** 读取观测到的安装策略说明文案。 */
|
|
81
|
+
export function settingsInstallNote(): string {
|
|
82
|
+
return observedInstall.note
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** 复位安装策略观测(测试隔离用)。 */
|
|
86
|
+
export function resetSettingsInstallObserved(): void {
|
|
87
|
+
observedInstall = { strategy: 'unknown', note: INSTALL_UNMOUNTED }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* 设置 section 版本自适应安装(核心策略分派)。
|
|
92
|
+
* legacy:dsh-settings 仍导出 installSettingsSection(rc 线)→ 原样调用,行为与旧版一致。
|
|
93
|
+
* service:该导出已移除(0.1.2-alpha 起)→ 经 ctx.inject(['settings']) 走服务方法
|
|
94
|
+
* provider.installSection(owner, ns, schema, entry, hooks)(等义封装,含
|
|
95
|
+
* base 层与 fiber 卸载回退)。回调内方法缺失再降级记录 none。
|
|
96
|
+
* none:两条路由都不存在 → 仅记录并告警,调用方按配置值运行。
|
|
97
|
+
* 全程不抛错、不产生未捕获 rejection。
|
|
98
|
+
* @author ddj 2026年09月02号
|
|
99
|
+
* @param ctx DSH host 上下文(inject 可选探测)
|
|
100
|
+
* @param ns 设置命名空间
|
|
101
|
+
* @param schema schemastery schema
|
|
102
|
+
* @param entry 初始设置值(作为 base 层)
|
|
103
|
+
* @param hooks 设置源绑定与变更回调
|
|
104
|
+
* @param loader 依赖装载器(测试注入)
|
|
105
|
+
* @returns 采用/观测到的策略
|
|
106
|
+
*/
|
|
107
|
+
export async function runSettingsInstall(
|
|
108
|
+
ctx: Ctx,
|
|
109
|
+
ns: string,
|
|
110
|
+
schema: unknown,
|
|
111
|
+
entry: object,
|
|
112
|
+
hooks: { setSource: (source: () => unknown) => void; onChange: () => void; validate?: unknown },
|
|
113
|
+
loader: SettingsDepsLoader = loadSettingsDeps,
|
|
114
|
+
): Promise<SettingsInstallStrategy> {
|
|
115
|
+
let deps: SettingsDeps | null = null
|
|
116
|
+
try {
|
|
117
|
+
deps = await loader()
|
|
118
|
+
} catch {
|
|
119
|
+
/* 装载失败按缺失处理 */
|
|
120
|
+
}
|
|
121
|
+
if (!deps) {
|
|
122
|
+
console.warn('[dsh-vscode-mode] 设置依赖不可用,section ' + ns + ' 未安装(配置回退)')
|
|
123
|
+
return recordInstall('none', INSTALL_NONE)
|
|
124
|
+
}
|
|
125
|
+
const legacy = deps.installSettingsSection
|
|
126
|
+
if (typeof legacy === 'function') {
|
|
127
|
+
try {
|
|
128
|
+
legacy(ctx, ns, schema, entry, hooks)
|
|
129
|
+
return recordInstall('legacy', INSTALL_LEGACY)
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.warn('[dsh-vscode-mode] legacy 设置安装失败,尝试服务路由:' + String(error))
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const ctxInject = (ctx as unknown as { inject?: (services: string[], callback: (sctx: unknown) => void) => unknown }).inject
|
|
135
|
+
if (typeof ctxInject !== 'function') return recordInstall('none', INSTALL_NONE)
|
|
136
|
+
try {
|
|
137
|
+
ctxInject(['settings'], (sctx: unknown) => {
|
|
138
|
+
const sc = sctx as { get?: (name: string) => unknown; settings?: unknown }
|
|
139
|
+
const provider = typeof sc.get === 'function' ? sc.get('settings') : sc.settings
|
|
140
|
+
const install = (provider as { installSection?: unknown } | undefined)?.installSection
|
|
141
|
+
if (typeof install !== 'function') {
|
|
142
|
+
console.warn('[dsh-vscode-mode] settings 服务无 installSection(DSH 版本 API 变化),section ' + ns + ' 降级为配置值')
|
|
143
|
+
recordInstall('none', INSTALL_NONE)
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
install.call(provider, ctx, ns, schema, entry, hooks)
|
|
148
|
+
recordInstall('service', INSTALL_SERVICE)
|
|
149
|
+
} catch (error) {
|
|
150
|
+
console.warn('[dsh-vscode-mode] settings.installSection 安装失败(' + String(error) + '),section ' + ns + ' 降级为配置值')
|
|
151
|
+
recordInstall('none', INSTALL_NONE)
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
} catch (error) {
|
|
155
|
+
console.warn('[dsh-vscode-mode] settings 服务路由不可用(' + String(error) + ')')
|
|
156
|
+
return recordInstall('none', INSTALL_NONE)
|
|
157
|
+
}
|
|
158
|
+
// inject 回调若同步执行(settings 已就绪)会覆写观测值;仍未执行(unknown)时乐观按 service 记录
|
|
159
|
+
if (observedInstall.strategy !== 'unknown') return observedInstall.strategy
|
|
160
|
+
return recordInstall('service', '已调度 settings 服务 installSection(等待 settings 就绪)')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 按命令目录构建 keybindings 显式键形状(每键独立默认值)。
|
|
165
|
+
* @author ddj 2026年08月26号
|
|
166
|
+
* @param z schemastery 命名空间
|
|
167
|
+
* @returns keybindings 字段形状
|
|
168
|
+
*/
|
|
169
|
+
function keybindingsShape(z: SettingsDeps['z']): Record<string, unknown> {
|
|
170
|
+
const shape: Record<string, unknown> = {}
|
|
171
|
+
for (const [id, chord] of Object.entries(KEYBINDING_DEFAULTS)) shape[id] = z.string().default(chord)
|
|
172
|
+
return shape
|
|
173
|
+
}
|
|
174
|
+
|
|
64
175
|
function normalizeValue(value: unknown): string {
|
|
65
176
|
if (typeof value !== 'string' || value.trim() === '') return FILE_OPEN_DEFAULT
|
|
66
177
|
return value.trim()
|
|
@@ -71,8 +182,8 @@ function configValue(config: unknown): string {
|
|
|
71
182
|
}
|
|
72
183
|
|
|
73
184
|
/**
|
|
74
|
-
* 安装设置 section
|
|
75
|
-
* @author ddj 2026年08月24号
|
|
185
|
+
* 安装设置 section(版本自适应;任一策略不可用返回 false 不抛错)。
|
|
186
|
+
* @author ddj 2026年08月24号 / 2026年09月02号
|
|
76
187
|
* @param ctx DSH host 上下文
|
|
77
188
|
* @param ns 设置命名空间
|
|
78
189
|
* @param entry 初始设置值
|
|
@@ -87,14 +198,22 @@ export async function installOpenSettingsSection(
|
|
|
87
198
|
hooks: { setSource: (source: () => FileOpenSettings) => void; onChange: () => void },
|
|
88
199
|
loader: SettingsDepsLoader = loadSettingsDeps,
|
|
89
200
|
): Promise<boolean> {
|
|
90
|
-
|
|
201
|
+
let deps: SettingsDeps | null = null
|
|
202
|
+
try {
|
|
203
|
+
deps = await loader()
|
|
204
|
+
} catch {
|
|
205
|
+
/* 装载失败按缺失处理 */
|
|
206
|
+
}
|
|
91
207
|
if (!deps) return false
|
|
92
208
|
const schema = deps.z.object({
|
|
93
209
|
fileOpenTool: deps.z.string().default(FILE_OPEN_DEFAULT),
|
|
94
210
|
keybindings: deps.z.object(keybindingsShape(deps.z)).default({ ...KEYBINDING_DEFAULTS }),
|
|
95
211
|
})
|
|
96
|
-
|
|
97
|
-
|
|
212
|
+
const strategy = await runSettingsInstall(ctx, ns, schema, entry, {
|
|
213
|
+
setSource: (source) => hooks.setSource(source as () => FileOpenSettings),
|
|
214
|
+
onChange: hooks.onChange,
|
|
215
|
+
}, loader)
|
|
216
|
+
return strategy === 'legacy' || strategy === 'service'
|
|
98
217
|
}
|
|
99
218
|
|
|
100
219
|
/**
|
package/src/host-deps.d.ts
CHANGED
|
@@ -3,12 +3,12 @@ declare module 'schemastery' {
|
|
|
3
3
|
export default schema
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
declare module '@deepseek-ai/dsh-settings' {
|
|
7
|
-
export function installSettingsSection(...args: any[]): void
|
|
8
|
-
export function settingsNamespace(value: string): string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
6
|
declare module '@deepseek-ai/schemastery' {
|
|
12
7
|
const schema: any
|
|
13
8
|
export default schema
|
|
14
9
|
}
|
|
10
|
+
|
|
11
|
+
// @deepseek-ai/dsh-settings 不在此声明:rc 线导出 installSettingsSection /
|
|
12
|
+
// settingsNamespace,0.1.2-alpha 起移除(改由 settings 服务 installSection 方法承载)。
|
|
13
|
+
// fileOpenSettings.ts 以动态导入 + 属性探测方式访问,见 SettingsDeps.installSettingsSection。
|
|
14
|
+
|
package/src/index.ts
CHANGED
|
@@ -92,7 +92,8 @@ async function logCompatSummary(ctx: Ctx, warnings: string[]): Promise<void> {
|
|
|
92
92
|
for (const warning of warnings) report.warnings.push(warning)
|
|
93
93
|
const logger = ctx.logger
|
|
94
94
|
if (!logger?.info) return
|
|
95
|
-
const
|
|
95
|
+
const dsh = report.dshVersion ? 'DSH ' + report.dshVersion : 'DSH 未探测'
|
|
96
|
+
const head = '[' + PLUGIN_NAME + '] 兼容性:' + dsh + ' · ' + report.external.length + ' 项外部适配 / ' + report.guards.length + ' 项护栏 / ' + (report.adapters?.length ?? 0) + ' 项版本适配'
|
|
96
97
|
if (report.warnings.length) {
|
|
97
98
|
logger.warn?.(head + ',警告 ' + report.warnings.length + ' 条:' + report.warnings.join(';'))
|
|
98
99
|
} else {
|
package/src/lsp/settings.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dsh-vscode-mode host — LSP 配置设置 section
|
|
2
|
+
* dsh-vscode-mode host — LSP 配置设置 section 安装(版本自适应;缺失/失败不抛错)。
|
|
3
3
|
* ns:dsh-vscode-mode.languageServers;每语言 { enabled, command, path }。
|
|
4
|
-
*
|
|
4
|
+
* 安装策略分派见 fileOpenSettings.runSettingsInstall(rc 线 legacy / alpha 线服务方法)。
|
|
5
|
+
* 作者 ddj 2026-08-27 / 2026-09-02
|
|
5
6
|
*/
|
|
6
7
|
import type { Ctx } from '../store.js'
|
|
7
8
|
import { LSP_LANGUAGES, LSP_SETTINGS_NS, type LspConfig } from './config.js'
|
|
8
|
-
import { loadSettingsDeps, type SettingsDeps } from '../fileOpenSettings.js'
|
|
9
|
+
import { loadSettingsDeps, runSettingsInstall, type SettingsDeps } from '../fileOpenSettings.js'
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* 安装 LSP 设置 section。
|
|
@@ -15,7 +16,12 @@ import { loadSettingsDeps, type SettingsDeps } from '../fileOpenSettings.js'
|
|
|
15
16
|
* @returns 是否成功安装
|
|
16
17
|
*/
|
|
17
18
|
export async function installLspSettingsSection(ctx: Ctx, entry: LspConfig): Promise<boolean> {
|
|
18
|
-
|
|
19
|
+
let deps: SettingsDeps | null = null
|
|
20
|
+
try {
|
|
21
|
+
deps = await loadSettingsDeps()
|
|
22
|
+
} catch {
|
|
23
|
+
/* 装载失败按缺失处理 */
|
|
24
|
+
}
|
|
19
25
|
if (!deps) return false
|
|
20
26
|
try {
|
|
21
27
|
// schemastery 无 .optional(),对象字段默认即可选;.default 必给避免 undefined 覆盖
|
|
@@ -29,11 +35,11 @@ export async function installLspSettingsSection(ctx: Ctx, entry: LspConfig): Pro
|
|
|
29
35
|
}).default({})
|
|
30
36
|
}
|
|
31
37
|
const schema = z.object(langShape).default({})
|
|
32
|
-
|
|
38
|
+
const strategy = await runSettingsInstall(ctx, LSP_SETTINGS_NS, schema, entry, {
|
|
33
39
|
setSource: () => {},
|
|
34
40
|
onChange: () => {},
|
|
35
41
|
})
|
|
36
|
-
return
|
|
42
|
+
return strategy === 'legacy' || strategy === 'service'
|
|
37
43
|
} catch (error) {
|
|
38
44
|
// 设置 section 安装失败不致命:降级为无设置 UI,LSP 核心功能不受影响
|
|
39
45
|
console.error('[dsh-vscode-mode] LSP 设置 section 安装失败:' + String(error))
|
package/src/shared/compat.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dsh-vscode-mode 兼容层双面契约 — 与其他插件 / DSH 版本的探测与自诊断报告。
|
|
3
3
|
* Purity rule: no node/react imports (same as types.ts / rpc.ts)。
|
|
4
|
-
* 作者 ddj 2026-08-24
|
|
4
|
+
* 作者 ddj 2026-08-24 / 2026-09-02
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
/**
|
|
7
|
+
/** 单项适配状态:外部插件/服务、护栏或版本适配项,active 表示健康/生效。 */
|
|
8
8
|
export interface CompatAdapter {
|
|
9
9
|
name: string
|
|
10
10
|
active: boolean
|
|
@@ -17,11 +17,17 @@ export interface DevFormInfo {
|
|
|
17
17
|
path?: string
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* 兼容性报告:host 侧构建(RPC edrv.compat 返回),client 侧补充本地适配项后展示。
|
|
22
|
+
* dshVersion = 运行中 DSH 核心版本(未探测到为空串);adapters = 版本适配机制状态行
|
|
23
|
+
* (旧客户端忽略未知字段,安全前向兼容)。
|
|
24
|
+
*/
|
|
21
25
|
export interface CompatReport {
|
|
22
26
|
pluginVersion: string
|
|
23
27
|
external: CompatAdapter[]
|
|
24
28
|
guards: CompatAdapter[]
|
|
25
29
|
warnings: string[]
|
|
26
30
|
devForm?: DevFormInfo
|
|
31
|
+
dshVersion?: string
|
|
32
|
+
adapters?: CompatAdapter[]
|
|
27
33
|
}
|