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.
@@ -1,8 +1,11 @@
1
1
  /**
2
2
  * dsh-vscode-mode host — 文件链接打开工具 + 快捷键的持久化设置。
3
- * 依赖守卫:@deepseek-ai/dsh-settings / schemastery 以动态加载引入,
4
- * 缺失时插件仍可加载(fileOpenTool 降级为配置值,compat 报告可见)。
5
- * 作者 ddj 2026年08月24号 / 2026年08月26号
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: (ctx: Ctx, ns: string, schema: unknown, entry: object, hooks: object) => void
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
- * 按命令目录构建 keybindings 显式键形状(每键独立默认值)。
37
- * @author ddj 2026年08月26号
38
- * @param z schemastery 命名空间
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
- installSettingsSection: (dshSettings as { installSettingsSection: SettingsDeps['installSettingsSection'] }).installSettingsSection,
57
- z: (schemastery as { default: SettingsDeps['z'] }).default,
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(动态依赖;缺失返回 false 不抛错)。
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
- const deps = await loader()
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
- deps.installSettingsSection(ctx, ns, schema, entry, hooks)
97
- return true
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
  /**
@@ -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 head = '[' + PLUGIN_NAME + '] 兼容性:' + report.external.length + ' 项外部适配 / ' + report.guards.length + ' 项护栏'
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 {
@@ -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
- * 作者 ddj 2026-08-27
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
- const deps = await loadSettingsDeps()
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
- deps.installSettingsSection(ctx, LSP_SETTINGS_NS, schema, entry, {
38
+ const strategy = await runSettingsInstall(ctx, LSP_SETTINGS_NS, schema, entry, {
33
39
  setSource: () => {},
34
40
  onChange: () => {},
35
41
  })
36
- return true
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))
@@ -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
- /** 单项适配状态:外部插件/服务或护栏项,active 表示健康/生效。 */
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
- /** 兼容性报告:host 侧构建(RPC edrv.compat 返回),client 侧补充本地适配项后展示。 */
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
  }