dsh-vscode-mode 0.7.0 → 0.9.0

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.
Files changed (60) hide show
  1. package/README.md +37 -6
  2. package/assets/icon.svg +7 -0
  3. package/cordis.patch.yml +16 -0
  4. package/lib/client.js +2804 -300
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +1975 -191
  7. package/lib/index.js.map +1 -1
  8. package/locale/en.json +4 -0
  9. package/locale/zh.json +4 -0
  10. package/package.json +4 -2
  11. package/src/ai/inline.ts +19 -2
  12. package/src/ai/svnTriage.ts +150 -0
  13. package/src/capture.ts +225 -51
  14. package/src/client/addToConversation.ts +203 -1
  15. package/src/client/compat.ts +134 -4
  16. package/src/client/imagePreview.ts +76 -2
  17. package/src/client/index.ts +65 -36
  18. package/src/client/monaco/lsp/lspClient.ts +46 -0
  19. package/src/client/monaco/lsp/providers.ts +245 -1
  20. package/src/client/nativeOpenStore.ts +91 -0
  21. package/src/client/officialSidebar.ts +11 -45
  22. package/src/client/outline/index.ts +1 -1
  23. package/src/client/pdf/pdfPanel.ts +18 -0
  24. package/src/client/pendingNav.ts +141 -0
  25. package/src/client/settingsContext.ts +6 -4
  26. package/src/client/sidebar/panels/FileExplorer.ts +2 -15
  27. package/src/client/sidebar/panels/SvnPanel.ts +682 -72
  28. package/src/client/sidebar/panels/index.ts +1 -1
  29. package/src/client/sidebar/panels/svnListBudget.ts +58 -0
  30. package/src/client/state/records.ts +7 -1
  31. package/src/client/styles/editor.css +47 -5
  32. package/src/client/svnStatus.ts +206 -1
  33. package/src/client/svnStore.ts +6 -1
  34. package/src/client/ui/AiSettings.ts +47 -14
  35. package/src/client/ui/DiffBox.ts +1 -1
  36. package/src/client/ui/DiffLauncher.ts +6 -4
  37. package/src/client/ui/EditorView.ts +149 -22
  38. package/src/client/ui/McpSettings.ts +30 -0
  39. package/src/client/ui/PerfSettings.ts +4 -1
  40. package/src/client/ui/SvnAiPlanDialog.ts +293 -0
  41. package/src/client/ui/icons.ts +91 -0
  42. package/src/compat.ts +26 -5
  43. package/src/dshVersion.ts +2 -1
  44. package/src/fileOpenSettings.ts +274 -49
  45. package/src/index.ts +18 -1
  46. package/src/lsp/client.ts +24 -0
  47. package/src/lsp/rpc.ts +57 -0
  48. package/src/lsp/server.ts +272 -2
  49. package/src/model.ts +2 -1
  50. package/src/perf.ts +90 -4
  51. package/src/remoteWorkspace.ts +177 -0
  52. package/src/routes.ts +13 -1
  53. package/src/rpc.ts +115 -39
  54. package/src/shared/ai.ts +12 -0
  55. package/src/shared/lsp.ts +79 -0
  56. package/src/shared/nativeOpen.ts +91 -0
  57. package/src/shared/rpc.ts +162 -2
  58. package/src/shared/svn.ts +296 -10
  59. package/src/shared/types.ts +5 -1
  60. package/src/svn.ts +235 -13
@@ -0,0 +1,141 @@
1
+ /**
2
+ * dsh-vscode-mode client — 跨挂载/跨热重载的待跳转交接(pending nav handoff)。
3
+ *
4
+ * 为什么必须落 window(第三次事故根因,2026-09-23 实测取证):
5
+ * 并行改码触发插件 client HMR 热重载(保留 console 中装配日志重复 6-7 轮为证)时,
6
+ * EditorView 被重挂载、模块级变量随 bundle 重求值复位——挂载级 `pendingFocusRef`
7
+ * 一并销毁,首开跳转只打开文件、不落目标行,热重载平息后的第二次点击才正常。
8
+ * window 属性跨热重载存活(先例:`__edrvLspProvidersRegistered__`、`__DSH_DEBUG_LOG__`)。
9
+ *
10
+ * 语义约定:
11
+ * - `putPendingNav` 写槽(openFileAt 与挂载级 ref 同步写,ref 是快路径、槽是交接路径);
12
+ * - `readPendingNav` **只读不消费**——过期/形状非法才清;新鲜槽可反复读;
13
+ * - 落点成功后由调用方 `clearPendingNav`(与 ref 同一清除点,防止残留二次跳);
14
+ * - TTL 到点自动失效,避免"稍后莫名跳一下"(用户已离开目标意图窗口)。
15
+ * 作者 ddj 2026-09-23
16
+ */
17
+
18
+ // --region 类型与常量
19
+
20
+ /** 待跳转形状(行列均 1-based;at = 写入时刻,TTL 判据)。 */
21
+ export interface PendingNav {
22
+ path: string
23
+ line?: number | null
24
+ column?: number | null
25
+ endLine?: number | null
26
+ endColumn?: number | null
27
+ at: number
28
+ }
29
+
30
+ /** 写入接口(at 由 putPendingNav 盖时间戳)。 */
31
+ export type PendingNavInput = Omit<PendingNav, 'at'>
32
+
33
+ /** window 槽键名(跨热重载存活的全局挂点)。 */
34
+ export const PENDING_NAV_KEY = '__edrvPendingNav__'
35
+
36
+ /** 交接有效期:超过即失效清槽(点击意图的有效窗口,防陈旧跳转)。 */
37
+ export const PENDING_NAV_TTL = 30000
38
+
39
+ // --endregion
40
+
41
+ // --region 纯函数(可单测)
42
+
43
+ /**
44
+ * 形状守卫:非法入参返回 null,合法则归一化为 PendingNav。
45
+ * 行列非有限数字一律归 null(缺省语义 = 不定位行),path 必须为非空字符串。
46
+ * @author ddj 2026年09月23号
47
+ * @param raw 任意来源的原始值
48
+ * @returns 归一化后的 PendingNav 或 null
49
+ */
50
+ export function sanitizeNav(raw: unknown): PendingNav | null {
51
+ if (!raw || typeof raw !== 'object') return null
52
+ const src = raw as Record<string, unknown>
53
+ if (typeof src.path !== 'string' || !src.path) return null
54
+ const num = (v: unknown): number | null => (typeof v === 'number' && Number.isFinite(v) ? v : null)
55
+ const at = num(src.at)
56
+ if (at === null) return null // at 是 TTL 判据:缺失/非法直接整体无效,不兜 0 免依赖巧合
57
+ return {
58
+ path: src.path,
59
+ line: num(src.line),
60
+ column: num(src.column),
61
+ endLine: num(src.endLine),
62
+ endColumn: num(src.endColumn),
63
+ at,
64
+ }
65
+ }
66
+
67
+ /**
68
+ * 新鲜度判定:形状合法且未超过 TTL 才算有效;过期返回 null。
69
+ * @author ddj 2026年09月23号
70
+ * @param nav 已归一化的待跳转(可空)
71
+ * @param now 当前时刻(毫秒)
72
+ * @param ttl 有效期(毫秒)
73
+ * @returns 有效导航或 null
74
+ */
75
+ export function freshNav(nav: PendingNav | null, now: number, ttl: number): PendingNav | null {
76
+ if (!nav) return null
77
+ return now - nav.at <= ttl ? nav : null
78
+ }
79
+
80
+ // --endregion
81
+
82
+ // --region window 槽适配
83
+
84
+ /** window 上的槽宿主(node 环境无 window,读写降级为 no-op)。 */
85
+ type NavSlotHost = Record<string, unknown>
86
+
87
+ /**
88
+ * 取槽宿主:仅浏览器环境返回 window,否则 undefined(测试/SSR 降级)。
89
+ * @author ddj 2026年09月23号
90
+ */
91
+ function slotHost(): NavSlotHost | undefined {
92
+ if (typeof window === 'undefined') return undefined
93
+ return window as unknown as NavSlotHost
94
+ }
95
+
96
+ /**
97
+ * 写入待跳转(盖写整槽;at 由调用方给定或取当前时间)。
98
+ * 非法 path 直接丢弃,不写槽。
99
+ * @author ddj 2026年09月23号
100
+ * @param nav 待跳转内容(不含 at)
101
+ * @param now 写入时刻(测试注入用)
102
+ * @returns 是否写入成功
103
+ */
104
+ export function putPendingNav(nav: PendingNavInput, now: number = Date.now()): boolean {
105
+ const host = slotHost()
106
+ if (!host) return false
107
+ if (typeof nav?.path !== 'string' || !nav.path) return false
108
+ host[PENDING_NAV_KEY] = { ...nav, at: now }
109
+ return true
110
+ }
111
+
112
+ /**
113
+ * 读取新鲜的待跳转(**不消费**;过期或形状非法才清槽)。
114
+ * @author ddj 2026年09月23号
115
+ * @param now 当前时刻(测试注入用)
116
+ * @param ttl 有效期(毫秒)
117
+ * @returns 有效导航或 null
118
+ */
119
+ export function readPendingNav(now: number = Date.now(), ttl: number = PENDING_NAV_TTL): PendingNav | null {
120
+ const host = slotHost()
121
+ if (!host) return null
122
+ const nav = freshNav(sanitizeNav(host[PENDING_NAV_KEY]), now, ttl)
123
+ if (!nav) {
124
+ // 失效即清:过期/垃圾数据不留在 window 上
125
+ if (host[PENDING_NAV_KEY] !== undefined) delete host[PENDING_NAV_KEY]
126
+ return null
127
+ }
128
+ return nav
129
+ }
130
+
131
+ /**
132
+ * 清除待跳转槽(落点成功或显式放弃时调用)。
133
+ * @author ddj 2026年09月23号
134
+ */
135
+ export function clearPendingNav(): void {
136
+ const host = slotHost()
137
+ if (!host) return
138
+ delete host[PENDING_NAV_KEY]
139
+ }
140
+
141
+ // --endregion
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * dsh-vscode-mode client — 设置 scope 的跨组件上下文。
3
- * 绑定逻辑(webUiSettings 兼容桥 → 官方 settingsScope 降级)统一由 compat 层提供。
4
- * 作者 ddj 2026年08月24号
3
+ * 绑定逻辑(configForms 0.1.7+ → webUiSettings 兼容桥 → 官方 settingsScope 降级,
4
+ * 带晚到有界重试)统一由 compat 层提供。
5
+ * 作者 ddj 2026年08月24号 / 2026年09月22号
5
6
  */
6
7
  import React from 'react'
7
8
  import { pickSettingsBinder, type SettingsScopeLike } from './compat.js'
@@ -11,8 +12,9 @@ export type { SettingsScopeLike }
11
12
  export const SettingsContext = React.createContext<SettingsScopeLike | undefined>(undefined)
12
13
 
13
14
  /**
14
- * 从 Cordis 服务绑定 VSCodeMode 设置 scope(兼容桥优先,官方次之)。
15
- * @author ddj 2026年08月24号
15
+ * 从 Cordis 服务绑定 VSCodeMode 设置 scope(四级桥:configForms/webUiSettings/settingsScope/无)。
16
+ * 每次调用重新探测——设置提供方晚到时后续渲染自然拿到新桥(自愈)。
17
+ * @author ddj 2026年08月24号(2026年09月22号 增补 configForms 级)
16
18
  * @param ctx 客户端服务上下文
17
19
  * @returns 设置 scope 或 undefined
18
20
  */
@@ -10,7 +10,7 @@
10
10
  * 作者 ddj 2026-08-26 / 2026-08-27 / 2026-08-31 / 2026-09-10 / 2026-09-16
11
11
  */
12
12
  import React from 'react'
13
- import { FileTypeIcon, IconFolderClose16, IconFolderOpen16, IconRefreshOutline16, classifyFileType } from '@deepseek-ai/dsh-client-ui-primitives'
13
+ import { IconFolderClose16, IconFolderOpen16, IconRefreshOutline16, fileIconEl } from '../../ui/icons.js'
14
14
  import { rpc } from '../../rpc.js'
15
15
  import { ContextMenu } from '../../ui/ContextMenu.js'
16
16
  import { buildTreeMenu } from '../contextMenu.js'
@@ -48,20 +48,7 @@ function dirIconEl(isOpen) {
48
48
  return React.createElement(Icon, { size: 16, className: 'edrv-tree-icon' })
49
49
  }
50
50
 
51
- /**
52
- * 文件图标元素(官方 FileTypeIcon + classifyFileType 分类,未知类型为 other)。
53
- * @author ddj 2026年09月10号
54
- * @param name 文件名(含扩展名)
55
- * @returns 图标元素;原语缺失或分类异常返回 null
56
- */
57
- function fileIconEl(name) {
58
- if (typeof FileTypeIcon !== 'function' || typeof classifyFileType !== 'function') return null
59
- try {
60
- return React.createElement(FileTypeIcon, { kind: classifyFileType(String(name ?? '')), size: 16, className: 'edrv-tree-icon' })
61
- } catch (error) {
62
- return null
63
- }
64
- }
51
+ // 文件图标元素(fileIconEl)已上移 icons.ts 共享(SVN 变更行同用),此处直接引用。
65
52
 
66
53
  /**
67
54
  * 行图标分派:目录 → 文件夹图标,文件 → 官方类型图标。