@jingyi0605/codingns4dsh 0.1.0 → 0.1.1

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 (216) hide show
  1. package/README.en.md +306 -0
  2. package/README.md +190 -993
  3. package/data/build/dist/client/account-bar.d.ts +2 -2
  4. package/data/build/dist/client/account-bar.js +96 -39
  5. package/data/build/dist/client/bundle.js +13722 -3611
  6. package/data/build/dist/client/cli-catalog.js +20 -3
  7. package/data/build/dist/client/cli-slots.d.ts +5 -0
  8. package/data/build/dist/client/cli-slots.js +57 -7
  9. package/data/build/dist/client/debug/ui.d.ts +1 -1
  10. package/data/build/dist/client/debug/ui.js +62 -32
  11. package/data/build/dist/client/dsh-runtime-version.d.ts +9 -2
  12. package/data/build/dist/client/dsh-runtime-version.js +24 -2
  13. package/data/build/dist/client/features/cli-adapters.d.ts +1 -1
  14. package/data/build/dist/client/features/cli-adapters.js +19 -16
  15. package/data/build/dist/client/features/debug.js +2 -2
  16. package/data/build/dist/client/features/index.d.ts +2 -1
  17. package/data/build/dist/client/features/index.js +3 -1
  18. package/data/build/dist/client/features/lan-access-panel.d.ts +1 -1
  19. package/data/build/dist/client/features/lan-access-panel.js +8 -10
  20. package/data/build/dist/client/features/lan-access.js +1 -1
  21. package/data/build/dist/client/features/login-protection-panel.d.ts +1 -1
  22. package/data/build/dist/client/features/login-protection-panel.js +7 -9
  23. package/data/build/dist/client/features/reverse-proxy-panel.d.ts +1 -1
  24. package/data/build/dist/client/features/reverse-proxy-panel.js +99 -11
  25. package/data/build/dist/client/features/reverse-proxy.d.ts +1 -1
  26. package/data/build/dist/client/features/reverse-proxy.js +19 -18
  27. package/data/build/dist/client/features/terminal-enhancement-panel.d.ts +1 -1
  28. package/data/build/dist/client/features/terminal-enhancement-panel.js +62 -55
  29. package/data/build/dist/client/features/terminal-enhancement.d.ts +1 -1
  30. package/data/build/dist/client/features/terminal-enhancement.js +3 -3
  31. package/data/build/dist/client/features/types.d.ts +14 -3
  32. package/data/build/dist/client/features/workspace-session-enhancement-panel.d.ts +1 -1
  33. package/data/build/dist/client/features/workspace-session-enhancement-panel.js +31 -9
  34. package/data/build/dist/client/features/workspace-session-enhancement.js +72 -11
  35. package/data/build/dist/client/git-management.d.ts +16 -0
  36. package/data/build/dist/client/git-management.js +757 -0
  37. package/data/build/dist/client/index.d.ts +3 -2
  38. package/data/build/dist/client/index.js +152 -27
  39. package/data/build/dist/client/locale.js +91 -29
  40. package/data/build/dist/client/quick-phrase-layout.d.ts +49 -0
  41. package/data/build/dist/client/quick-phrase-layout.js +95 -0
  42. package/data/build/dist/client/quick-phrase-slot.d.ts +7 -0
  43. package/data/build/dist/client/quick-phrase-slot.js +370 -0
  44. package/data/build/dist/client/remote-web-context.js +1 -1
  45. package/data/build/dist/client/settings-bridge.d.ts +9 -6
  46. package/data/build/dist/client/settings-bridge.js +51 -27
  47. package/data/build/dist/client/settings-section.d.ts +3 -2
  48. package/data/build/dist/client/settings-section.js +33 -19
  49. package/data/build/dist/client/subscription-slot.d.ts +3 -0
  50. package/data/build/dist/client/subscription-slot.js +108 -16
  51. package/data/build/dist/client/terminal/model.d.ts +14 -2
  52. package/data/build/dist/client/terminal/model.js +109 -21
  53. package/data/build/dist/client/terminal/recovery.d.ts +50 -0
  54. package/data/build/dist/client/terminal/recovery.js +101 -0
  55. package/data/build/dist/client/terminal/ui.d.ts +2 -2
  56. package/data/build/dist/client/terminal/ui.js +49 -11
  57. package/data/build/dist/client/terminal/xterm-view.d.ts +2 -2
  58. package/data/build/dist/client/terminal/xterm-view.js +2 -1
  59. package/data/build/dist/client/theme.d.ts +6 -1
  60. package/data/build/dist/client/theme.js +32 -1
  61. package/data/build/dist/client/workspace-session-archive-dom.d.ts +12 -0
  62. package/data/build/dist/client/workspace-session-archive-dom.js +27 -5
  63. package/data/build/dist/client/workspace-session-visibility-dom.d.ts +30 -0
  64. package/data/build/dist/client/workspace-session-visibility-dom.js +604 -0
  65. package/data/build/dist/dsh-capabilities/client/config-forms-adapter.d.ts +50 -0
  66. package/data/build/dist/dsh-capabilities/client/config-forms-adapter.js +139 -0
  67. package/data/build/dist/dsh-capabilities/client/conversation-adapter.d.ts +7 -0
  68. package/data/build/dist/dsh-capabilities/client/conversation-adapter.js +6 -0
  69. package/data/build/dist/dsh-capabilities/client/locale-adapter.d.ts +9 -0
  70. package/data/build/dist/dsh-capabilities/client/locale-adapter.js +4 -0
  71. package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts +10 -0
  72. package/data/build/dist/dsh-capabilities/client/primitives-adapter.js +14 -0
  73. package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.d.ts +8 -0
  74. package/data/build/dist/dsh-capabilities/client/settings-scope-adapter.js +16 -0
  75. package/data/build/dist/dsh-capabilities/client/sidebar-adapter.d.ts +7 -0
  76. package/data/build/dist/dsh-capabilities/client/sidebar-adapter.js +5 -0
  77. package/data/build/dist/dsh-capabilities/client/theme-adapter.d.ts +6 -0
  78. package/data/build/dist/dsh-capabilities/client/theme-adapter.js +4 -0
  79. package/data/build/dist/dsh-capabilities/client/typert-adapter.d.ts +5 -0
  80. package/data/build/dist/dsh-capabilities/client/typert-adapter.js +4 -0
  81. package/data/build/dist/dsh-capabilities/host/config-forms-adapter.d.ts +19 -0
  82. package/data/build/dist/dsh-capabilities/host/config-forms-adapter.js +45 -0
  83. package/data/build/dist/dsh-capabilities/host/connection-rpc-adapter.d.ts +19 -0
  84. package/data/build/dist/dsh-capabilities/host/connection-rpc-adapter.js +13 -0
  85. package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.d.ts +8 -0
  86. package/data/build/dist/dsh-capabilities/host/settings-scope-adapter.js +47 -0
  87. package/data/build/dist/dsh-capabilities/host/typert-adapter.d.ts +6 -0
  88. package/data/build/dist/dsh-capabilities/host/typert-adapter.js +4 -0
  89. package/data/build/dist/dsh-capabilities/index.d.ts +6 -0
  90. package/data/build/dist/dsh-capabilities/index.js +6 -0
  91. package/data/build/dist/dsh-capabilities/matrix.d.ts +15 -0
  92. package/data/build/dist/dsh-capabilities/matrix.js +32 -0
  93. package/data/build/dist/dsh-capabilities/registry.d.ts +22 -0
  94. package/data/build/dist/dsh-capabilities/registry.js +196 -0
  95. package/data/build/dist/dsh-capabilities/routes.d.ts +10 -0
  96. package/data/build/dist/dsh-capabilities/routes.js +34 -0
  97. package/data/build/dist/dsh-capabilities/settings-store.d.ts +29 -0
  98. package/data/build/dist/dsh-capabilities/settings-store.js +5 -0
  99. package/data/build/dist/dsh-capabilities/types.d.ts +50 -0
  100. package/data/build/dist/dsh-capabilities/types.js +23 -0
  101. package/data/build/dist/features/registry.d.ts +8 -2
  102. package/data/build/dist/features/registry.js +104 -1
  103. package/data/build/dist/host/auth-session.d.ts +8 -1
  104. package/data/build/dist/host/auth-session.js +28 -6
  105. package/data/build/dist/host/cli-adapters/claude-driver.d.ts +2 -0
  106. package/data/build/dist/host/cli-adapters/claude-driver.js +19 -4
  107. package/data/build/dist/host/cli-adapters/claude-model-options.d.ts +14 -0
  108. package/data/build/dist/host/cli-adapters/claude-model-options.js +157 -0
  109. package/data/build/dist/host/cli-adapters/codex-driver.d.ts +11 -0
  110. package/data/build/dist/host/cli-adapters/codex-driver.js +166 -14
  111. package/data/build/dist/host/cli-adapters/driver.d.ts +2 -0
  112. package/data/build/dist/host/cli-adapters/dsh-message-projector.d.ts +15 -0
  113. package/data/build/dist/host/cli-adapters/dsh-message-projector.js +120 -29
  114. package/data/build/dist/host/cli-adapters/dsh-tool-history.d.ts +4 -1
  115. package/data/build/dist/host/cli-adapters/dsh-tool-history.js +25 -7
  116. package/data/build/dist/host/cli-adapters/feature.js +74 -8
  117. package/data/build/dist/host/cli-adapters/gemini-driver.js +2 -2
  118. package/data/build/dist/host/cli-adapters/grok-driver.js +2 -2
  119. package/data/build/dist/host/cli-adapters/json-rpc-process.d.ts +4 -2
  120. package/data/build/dist/host/cli-adapters/json-rpc-process.js +8 -9
  121. package/data/build/dist/host/cli-adapters/kimi-driver.js +1 -1
  122. package/data/build/dist/host/cli-adapters/legacy-session-adapter.d.ts +17 -0
  123. package/data/build/dist/host/cli-adapters/legacy-session-adapter.js +88 -0
  124. package/data/build/dist/host/cli-adapters/legacy-session-settings.d.ts +24 -0
  125. package/data/build/dist/host/cli-adapters/legacy-session-settings.js +162 -0
  126. package/data/build/dist/host/cli-adapters/official-provider-subscription.d.ts +29 -0
  127. package/data/build/dist/host/cli-adapters/official-provider-subscription.js +361 -0
  128. package/data/build/dist/host/cli-adapters/opencode-driver.d.ts +2 -0
  129. package/data/build/dist/host/cli-adapters/opencode-driver.js +97 -12
  130. package/data/build/dist/host/cli-adapters/pi-driver.js +69 -23
  131. package/data/build/dist/host/cli-adapters/provider-registry.d.ts +33 -0
  132. package/data/build/dist/host/cli-adapters/provider-registry.js +83 -0
  133. package/data/build/dist/host/cli-adapters/provider-subscription.d.ts +25 -3
  134. package/data/build/dist/host/cli-adapters/provider-subscription.js +346 -30
  135. package/data/build/dist/host/cli-adapters/registry.d.ts +6 -0
  136. package/data/build/dist/host/cli-adapters/registry.js +170 -13
  137. package/data/build/dist/host/cli-adapters/rpc-driver-utils.js +10 -0
  138. package/data/build/dist/host/cli-adapters/session-store.d.ts +7 -0
  139. package/data/build/dist/host/cli-adapters/session-store.js +39 -1
  140. package/data/build/dist/host/cli-adapters/standard-stream-driver.d.ts +3 -0
  141. package/data/build/dist/host/cli-adapters/stream-normalizer.d.ts +3 -0
  142. package/data/build/dist/host/cli-adapters/stream-normalizer.js +22 -2
  143. package/data/build/dist/host/control-api-client.d.ts +3 -3
  144. package/data/build/dist/host/control-api-client.js +2 -1
  145. package/data/build/dist/host/credential-store.js +11 -1
  146. package/data/build/dist/host/dsh-device-runtime.d.ts +4 -0
  147. package/data/build/dist/host/dsh-device-runtime.js +20 -9
  148. package/data/build/dist/host/dsh-runtime-version.d.ts +3 -2
  149. package/data/build/dist/host/dsh-runtime-version.js +71 -2
  150. package/data/build/dist/host/features/auth.js +8 -5
  151. package/data/build/dist/host/features/debug.js +1 -1
  152. package/data/build/dist/host/features/git-management.d.ts +5 -0
  153. package/data/build/dist/host/features/git-management.js +290 -0
  154. package/data/build/dist/host/features/host-status.js +1 -1
  155. package/data/build/dist/host/features/index.d.ts +1 -0
  156. package/data/build/dist/host/features/index.js +3 -0
  157. package/data/build/dist/host/features/terminal-process.js +1 -1
  158. package/data/build/dist/host/features/terminal-status.d.ts +3 -1
  159. package/data/build/dist/host/features/terminal-status.js +3 -1
  160. package/data/build/dist/host/index.d.ts +7 -3
  161. package/data/build/dist/host/index.js +79 -15
  162. package/data/build/dist/host/lan-access-dsh.js +18 -5
  163. package/data/build/dist/host/native-session-bridge.d.ts +23 -1
  164. package/data/build/dist/host/native-session-bridge.js +157 -10
  165. package/data/build/dist/host/rpc-table.d.ts +1 -1
  166. package/data/build/dist/host/rpc.js +60 -10
  167. package/data/build/dist/host/session-migration-repair.d.ts +19 -0
  168. package/data/build/dist/host/session-migration-repair.js +395 -0
  169. package/data/build/dist/host/settings.d.ts +8 -1
  170. package/data/build/dist/host/settings.js +94 -3
  171. package/data/build/dist/host/terminal/backends/tmux-backend.d.ts +1 -0
  172. package/data/build/dist/host/terminal/backends/tmux-backend.js +4 -2
  173. package/data/build/dist/host/terminal/controller-factory.d.ts +4 -0
  174. package/data/build/dist/host/terminal/controller-factory.js +26 -7
  175. package/data/build/dist/host/terminal/runtime-manager.d.ts +2 -1
  176. package/data/build/dist/host/terminal/runtime-manager.js +3 -0
  177. package/data/build/dist/host/terminal/startup.d.ts +2 -0
  178. package/data/build/dist/host/terminal/startup.js +2 -1
  179. package/data/build/dist/host/terminal/terminal-controller.d.ts +10 -3
  180. package/data/build/dist/host/terminal/terminal-controller.js +101 -15
  181. package/data/build/dist/host/terminal/terminal-process-service.js +3 -1
  182. package/data/build/dist/host/terminal/terminal-service.d.ts +2 -0
  183. package/data/build/dist/host/terminal/terminal-service.js +10 -0
  184. package/data/build/dist/index.d.ts +6 -2
  185. package/data/build/dist/index.js +8 -2
  186. package/data/build/dist/shared/contracts/cli-adapter.d.ts +14 -0
  187. package/data/build/dist/shared/contracts/config.d.ts +31 -1
  188. package/data/build/dist/shared/contracts/config.js +25 -0
  189. package/data/build/dist/shared/contracts/dsh-device.d.ts +13 -1
  190. package/data/build/dist/shared/contracts/errors.d.ts +1 -1
  191. package/data/build/dist/shared/contracts/feature.d.ts +6 -0
  192. package/data/build/dist/shared/contracts/git.d.ts +82 -0
  193. package/data/build/dist/shared/contracts/git.js +3 -0
  194. package/data/build/dist/shared/contracts/subscription.d.ts +46 -0
  195. package/data/build/dist/shared/contracts/terminal.d.ts +4 -1
  196. package/data/build/dist/shared/contracts/version.d.ts +2 -2
  197. package/data/build/dist/shared/contracts/version.js +4 -6
  198. package/data/build/dist/shared/debug.d.ts +14 -0
  199. package/data/build/dist/shared/debug.js +53 -0
  200. package/data/build/dist/shared/index.d.ts +7 -4
  201. package/data/build/dist/shared/index.js +2 -1
  202. package/data/build/dist/transport/debug.d.ts +1 -1
  203. package/data/build/dist/transport/debug.js +3 -30
  204. package/data/build/dist/transport/dsh-session.js +3 -3
  205. package/data/build/dist/typert.host.d.ts +1 -1
  206. package/data/build/dist/typert.host.js +6 -3
  207. package/data/build/dist/typert.remote-client.d.ts +11 -0
  208. package/data/build/dist/typert.remote-client.js +7 -0
  209. package/dsh.bundle.patch +1 -1
  210. package/package.json +13 -5
  211. package/profile/README.md +4 -4
  212. package/profile/package.json +6 -4
  213. package/profile/scripts/check-dsh-install.mjs +2 -2
  214. package/profile/version.json +2 -2
  215. package/scripts/check-dsh-install.mjs +2 -2
  216. package/version.json +2 -2
@@ -1,5 +1,6 @@
1
1
  import z from '@deepseek-ai/schemastery';
2
- import { CODINGNS_SETTINGS_NAMESPACE, DEFAULT_CODINGNS_SETTINGS, } from '../shared/contracts/config.js';
2
+ import { CODINGNS_SETTINGS_NAMESPACE, isCodingNsSettingsEntryId, DEFAULT_CODINGNS_SETTINGS, } from '../shared/contracts/config.js';
3
+ import { debugInfo } from '../shared/debug.js';
3
4
  /**
4
5
  * DSH 设置服务使用的 Codingns4DSH namespace schema。
5
6
  *
@@ -55,9 +56,26 @@ export const CodingNsSettingsSchema = z.object({
55
56
  workspaceSessionEnhancement: z.object({
56
57
  showAdapterLogo: z.boolean().default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement.showAdapterLogo),
57
58
  showArchivedSessions: z.boolean().default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement.showArchivedSessions),
59
+ showWorkspaceHiding: z.boolean().default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement.showWorkspaceHiding),
60
+ hiddenWorkspaceIds: z.array(z.string().min(1).max(512)).default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement.hiddenWorkspaceIds),
58
61
  showSubscriptionUsage: z.boolean().default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement.showSubscriptionUsage),
62
+ showQuickPhrases: z.boolean().default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement.showQuickPhrases),
63
+ quickPhrases: z.array(z.object({
64
+ id: z.string().min(1).max(128),
65
+ text: z.string().min(1).max(4000),
66
+ })).default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement.quickPhrases),
67
+ // 缺少该字段说明是旧配置;Client 首次加载时会补齐内置快捷会话。
68
+ quickPhrasesSeeded: z.boolean().default(false),
59
69
  }).default(DEFAULT_CODINGNS_SETTINGS.workspaceSessionEnhancement),
60
70
  });
71
+ /**
72
+ * DSH 0.1.7 只会把 `volatile` 配置投影成可编辑 ConfigForm。
73
+ *
74
+ * 整个根节点标记为 volatile,保留 Host 侧 `cliSessions` 的持久化能力;
75
+ * Client 适配器会在镜像配置时剔除这个 Host-only 字段,避免会话索引进入浏览器。
76
+ */
77
+ export const CodingNsConfigSchema = CodingNsSettingsSchema.volatile();
78
+ let lastConfigDescriptorSignature;
61
79
  /** 颜色字段只接受完整十六进制颜色,`null` 表示继承 DSH 原生值。 */
62
80
  function nullableColorSchema() {
63
81
  return z.union([z.string().pattern(/^#[0-9A-Fa-f]{6}$/u), z.const(null)]).default(null);
@@ -73,8 +91,81 @@ function nullableNumberSchema(min, max) {
73
91
  */
74
92
  export function registerCodingNsSettings(ctx) {
75
93
  const settings = ctx.settings;
76
- return settings.register(CODINGNS_SETTINGS_NAMESPACE, CodingNsSettingsSchema, {
77
- applies: 'live',
94
+ const legacyRegister = settings.register;
95
+ if (typeof legacyRegister === 'function') {
96
+ debugInfo('codingns4dsh: host settings source=legacy-settings');
97
+ return legacyRegister.call(settings, CODINGNS_SETTINGS_NAMESPACE, CodingNsSettingsSchema, {
98
+ applies: 'live',
99
+ });
100
+ }
101
+ debugInfo('codingns4dsh: host settings source=config-forms');
102
+ return createConfigSettingsScope(ctx, settings);
103
+ }
104
+ /** 将 DSH 0.1.7 SettingsForms 适配成 Host 业务沿用的 SettingsScope。 */
105
+ function createConfigSettingsScope(ctx, settings) {
106
+ const provider = settings;
107
+ let previous = readConfigSettings(provider);
108
+ const listeners = new Set();
109
+ const eventContext = ctx;
110
+ const disposeEvent = eventContext.on?.('settings/document-updated', (namespace) => {
111
+ if (!isCodingNsSettingsNamespace(namespace))
112
+ return;
113
+ const next = readConfigSettings(provider);
114
+ const prev = previous;
115
+ previous = next;
116
+ if (next === prev)
117
+ return;
118
+ for (const listener of [...listeners])
119
+ void listener(next, prev);
78
120
  });
121
+ if (disposeEvent !== undefined) {
122
+ ctx.effect(() => disposeEvent, 'codingns4dsh: ConfigForm 设置监听');
123
+ }
124
+ return {
125
+ get: () => readConfigSettings(provider),
126
+ watch: (listener) => {
127
+ listeners.add(listener);
128
+ return () => listeners.delete(listener);
129
+ },
130
+ update: async (patch) => {
131
+ if (typeof provider.update !== 'function')
132
+ throw new Error('DSH ConfigForms 不支持 update');
133
+ await provider.update(resolveConfigSettingsNamespace(provider), patch);
134
+ },
135
+ replace: async (section) => {
136
+ if (typeof provider.replace !== 'function')
137
+ throw new Error('DSH ConfigForms 不支持 replace');
138
+ await provider.replace(resolveConfigSettingsNamespace(provider), section);
139
+ },
140
+ };
141
+ }
142
+ function readConfigSettings(settings) {
143
+ const descriptor = findConfigSettingsDescriptor(settings);
144
+ if (descriptor === undefined) {
145
+ console.warn('codingns4dsh: host ConfigForms 未找到设置 namespace,使用默认值');
146
+ return DEFAULT_CODINGNS_SETTINGS;
147
+ }
148
+ return descriptor.value;
149
+ }
150
+ /** DSH 0.1.7 使用插件 entry id;旧 SettingsScope 使用显式 namespace。 */
151
+ function findConfigSettingsDescriptor(settings) {
152
+ const descriptors = settings.describe({ redactSecrets: false });
153
+ const signature = JSON.stringify(descriptors.map((item) => ({
154
+ ns: item.ns,
155
+ revision: item.revision,
156
+ writable: item.writable,
157
+ hasValue: item.value !== undefined,
158
+ })));
159
+ if (signature !== lastConfigDescriptorSignature) {
160
+ lastConfigDescriptorSignature = signature;
161
+ debugInfo('codingns4dsh: host ConfigForms descriptors', JSON.parse(signature));
162
+ }
163
+ return descriptors.find((item) => isCodingNsSettingsNamespace(item.ns));
164
+ }
165
+ function resolveConfigSettingsNamespace(settings) {
166
+ return findConfigSettingsDescriptor(settings)?.ns ?? CODINGNS_SETTINGS_NAMESPACE;
167
+ }
168
+ function isCodingNsSettingsNamespace(namespace) {
169
+ return isCodingNsSettingsEntryId(namespace);
79
170
  }
80
171
  //# sourceMappingURL=settings.js.map
@@ -37,4 +37,5 @@ export declare class TmuxTerminalBackend implements TerminalRuntimeAdapter {
37
37
  private requireTmuxPath;
38
38
  }
39
39
  export declare function tmuxSessionName(runtimeSessionKey: string): string;
40
+ export declare function detectTmuxPath(platform: string, pathValue?: string | undefined): string | null;
40
41
  //# sourceMappingURL=tmux-backend.d.ts.map
@@ -166,10 +166,12 @@ export function tmuxSessionName(runtimeSessionKey) {
166
166
  function runCommand(command, args) {
167
167
  return spawnSync(command, args, { encoding: 'utf8', windowsHide: true, shell: false });
168
168
  }
169
- function detectTmuxPath(platform) {
170
- const candidates = platform === 'darwin'
169
+ export function detectTmuxPath(platform, pathValue = process.env.PATH) {
170
+ const fixedCandidates = platform === 'darwin'
171
171
  ? ['/opt/homebrew/bin/tmux', '/usr/local/bin/tmux', '/usr/bin/tmux']
172
172
  : ['/usr/bin/tmux', '/usr/local/bin/tmux', '/bin/tmux'];
173
+ const pathCandidates = (pathValue ?? '').split(':').filter(Boolean).map((directory) => `${directory}/tmux`);
174
+ const candidates = [...new Set([...fixedCandidates, ...pathCandidates])];
173
175
  return candidates.find(isExecutable) ?? null;
174
176
  }
175
177
  function isExecutable(path) {
@@ -1,5 +1,6 @@
1
1
  import type { Context } from '@deepseek-ai/cordis';
2
2
  import type { TerminalEnhancementSettings } from '../../shared/contracts/config.js';
3
+ import type { CodingNsTerminalRuntimeType } from '../../shared/contracts/terminal.js';
3
4
  import { CodingNsTerminalController, type DshTerminalAgent } from './terminal-controller.js';
4
5
  import type { TerminalRuntimeAdapter } from './runtime-adapter.js';
5
6
  import { CodingNsTerminalService } from './terminal-service.js';
@@ -9,6 +10,7 @@ interface TerminalControllerFactoryCommonOptions {
9
10
  readonly platform?: string;
10
11
  readonly generation?: (agent: DshTerminalAgent, attachmentId: string) => string;
11
12
  readonly workspaceId?: (agent: DshTerminalAgent, cwd: string) => string;
13
+ readonly registerWorkspaceRoot?: (workspaceId: string, cwd: string) => void;
12
14
  readonly resolveWorkspaceRoot?: (workspaceId: string) => string | null;
13
15
  }
14
16
  export type TerminalControllerFactoryOptions = TerminalControllerFactoryCommonOptions & ({
@@ -22,6 +24,8 @@ export type TerminalControllerFactoryOptions = TerminalControllerFactoryCommonOp
22
24
  });
23
25
  export interface TerminalControllerFactoryResult {
24
26
  readonly mode: 'baseline' | 'enhanced';
27
+ readonly runtimeTypes: readonly CodingNsTerminalRuntimeType[];
28
+ readonly runtimeWarning?: string;
25
29
  readonly controller: CodingNsTerminalController;
26
30
  readonly service: CodingNsTerminalService;
27
31
  readonly processService: TerminalProcessService;
@@ -1,6 +1,6 @@
1
1
  import { ConptyTerminalBackend } from './backends/conpty-backend.js';
2
2
  import { LocalPtyTerminalBackend } from './backends/local-pty-backend.js';
3
- import { TmuxTerminalBackend } from './backends/tmux-backend.js';
3
+ import { detectTmuxPath, TmuxTerminalBackend } from './backends/tmux-backend.js';
4
4
  import { CodingNsTerminalController } from './terminal-controller.js';
5
5
  import { TerminalRuntimeManager } from './runtime-manager.js';
6
6
  import { CodingNsTerminalService } from './terminal-service.js';
@@ -16,12 +16,21 @@ import { TerminalProcessService } from './terminal-process-service.js';
16
16
  export async function createTerminalController(ctx, options) {
17
17
  const platform = options.platform ?? process.platform;
18
18
  if (!options.enhancedEnabled) {
19
- const backend = options.baselineBackend ?? new LocalPtyTerminalBackend({ platform });
19
+ const localBackend = options.baselineBackend ?? new LocalPtyTerminalBackend({ platform });
20
+ const tmuxPath = platform === 'darwin' || platform === 'linux' ? detectTmuxPath(platform) : null;
21
+ const tmuxBackend = tmuxPath === null || localBackend.runtimeTypes.includes('tmux')
22
+ ? undefined
23
+ : new TmuxTerminalBackend({ platform, tmuxPath });
24
+ const backends = tmuxBackend === undefined ? [localBackend] : [localBackend, tmuxBackend];
20
25
  return assembleController(ctx, {
21
26
  mode: 'baseline',
22
27
  hostId: 'local-baseline',
23
28
  store: new CodingNsTerminalStore(new InMemoryTerminalStorePersistence()),
24
- backend,
29
+ backends,
30
+ runtimeTypes: backends.flatMap((backend) => backend.runtimeTypes),
31
+ ...(tmuxBackend === undefined && !localBackend.runtimeTypes.includes('tmux') && (platform === 'darwin' || platform === 'linux')
32
+ ? { runtimeWarning: '未检测到可执行的 tmux,调试终端将回退到 local-pty。' }
33
+ : {}),
25
34
  processStore: new TerminalProcessStore(new InMemoryTerminalProcessStorePersistence()),
26
35
  settings: options.settings,
27
36
  platform,
@@ -31,24 +40,31 @@ export async function createTerminalController(ctx, options) {
31
40
  ...(options.resolveWorkspaceRoot === undefined ? {} : { resolveWorkspaceRoot: options.resolveWorkspaceRoot }),
32
41
  });
33
42
  }
34
- const backend = platform === 'win32'
43
+ const localBackend = new LocalPtyTerminalBackend({ platform });
44
+ const tmuxPath = platform === 'darwin' || platform === 'linux' ? detectTmuxPath(platform) : null;
45
+ const enhancedBackend = platform === 'win32'
35
46
  ? new ConptyTerminalBackend({ platform })
36
- : new TmuxTerminalBackend({ platform });
47
+ : tmuxPath === null ? localBackend : new TmuxTerminalBackend({ platform, tmuxPath });
48
+ const runtimeTypes = [...enhancedBackend.runtimeTypes];
37
49
  return assembleController(ctx, {
38
50
  mode: 'enhanced',
39
51
  hostId: options.hostId,
40
52
  store: new CodingNsTerminalStore(new JsonFileTerminalStorePersistence(options.storeFilename)),
41
53
  processStore: new TerminalProcessStore(new JsonFileTerminalProcessStorePersistence(options.processStoreFilename ?? `${options.storeFilename}.processes`)),
42
- backend,
54
+ backends: [enhancedBackend],
55
+ runtimeTypes,
56
+ ...(enhancedBackend === localBackend ? { runtimeWarning: '未检测到可执行的 tmux,终端已回退到 local-pty。' } : {}),
57
+ ...(enhancedBackend === localBackend ? { runtimeType: () => 'local-pty' } : {}),
43
58
  settings: options.settings,
44
59
  platform,
45
60
  ...(options.generation === undefined ? {} : { generation: options.generation }),
46
61
  ...(options.workspaceId === undefined ? {} : { workspaceId: options.workspaceId }),
62
+ ...(options.registerWorkspaceRoot === undefined ? {} : { registerWorkspaceRoot: options.registerWorkspaceRoot }),
47
63
  ...(options.resolveWorkspaceRoot === undefined ? {} : { resolveWorkspaceRoot: options.resolveWorkspaceRoot }),
48
64
  });
49
65
  }
50
66
  async function assembleController(ctx, options) {
51
- const service = new CodingNsTerminalService(options.store, new TerminalRuntimeManager([options.backend]));
67
+ const service = new CodingNsTerminalService(options.store, new TerminalRuntimeManager(options.backends));
52
68
  await service.initialize();
53
69
  if (options.mode === 'enhanced')
54
70
  await service.recover();
@@ -59,6 +75,7 @@ async function assembleController(ctx, options) {
59
75
  ...(options.platform === undefined ? {} : { platform: options.platform }),
60
76
  ...(options.generation === undefined ? {} : { generation: options.generation }),
61
77
  ...(options.workspaceId === undefined ? {} : { workspaceId: options.workspaceId }),
78
+ ...(options.registerWorkspaceRoot === undefined ? {} : { registerWorkspaceRoot: options.registerWorkspaceRoot }),
62
79
  ...(options.runtimeType === undefined ? {} : { runtimeType: options.runtimeType }),
63
80
  });
64
81
  const processService = new TerminalProcessService(options.processStore, {
@@ -74,6 +91,8 @@ async function assembleController(ctx, options) {
74
91
  : 'codingns4dsh: 持久终端 attach 清理');
75
92
  return {
76
93
  mode: options.mode,
94
+ runtimeTypes: options.runtimeTypes,
95
+ ...(options.runtimeWarning === undefined ? {} : { runtimeWarning: options.runtimeWarning }),
77
96
  controller,
78
97
  service,
79
98
  processService,
@@ -1,6 +1,6 @@
1
1
  import type { PersistentTerminalRecord, TerminalRecordIdentity } from '../../shared/contracts/terminal.js';
2
2
  import { type ManagedTerminalAttachment } from './attachment-registry.js';
3
- import type { TerminalRuntimeAdapter, TerminalRuntimeIdentity } from './runtime-adapter.js';
3
+ import type { TerminalRuntimeAdapter, TerminalRuntimeIdentity, TerminalRuntimeType } from './runtime-adapter.js';
4
4
  export interface RuntimeAttachmentInput {
5
5
  readonly identity: TerminalRecordIdentity;
6
6
  readonly generation: string;
@@ -17,6 +17,7 @@ export declare class TerminalRuntimeManager {
17
17
  private readonly registry;
18
18
  private readonly monitors;
19
19
  constructor(adapters: readonly TerminalRuntimeAdapter[]);
20
+ supports(runtimeType: TerminalRuntimeType): boolean;
20
21
  create(record: PersistentTerminalRecord): Promise<TerminalRuntimeIdentity>;
21
22
  inspect(record: PersistentTerminalRecord): Promise<TerminalRuntimeIdentity>;
22
23
  attach(record: PersistentTerminalRecord, input: RuntimeAttachmentInput): Promise<ManagedTerminalAttachment>;
@@ -14,6 +14,9 @@ export class TerminalRuntimeManager {
14
14
  }
15
15
  }
16
16
  }
17
+ supports(runtimeType) {
18
+ return this.adapters.has(runtimeType);
19
+ }
17
20
  create(record) {
18
21
  return this.adapter(record.runtimeType).create({ session: runtimeSession(record), cols: record.cols, rows: record.rows });
19
22
  }
@@ -13,6 +13,8 @@ export interface InstallTerminalControllerOptions {
13
13
  readonly resolveIdentity?: (settingsDocumentPath: string) => Promise<TerminalStartupIdentity>;
14
14
  /** 由 Host 解析稳定 Workspace ID 到受信任根目录;不能接收浏览器传来的绝对路径。 */
15
15
  readonly resolveWorkspaceRoot?: (workspaceId: string) => string | null;
16
+ /** 由终端 controller 在 Host 侧登记可信 Workspace 根目录。 */
17
+ readonly registerWorkspaceRoot?: (workspaceId: string, cwd: string) => void;
16
18
  }
17
19
  /**
18
20
  * 从 DSH 设置文档旁边的持久目录读取本机终端身份。
@@ -61,13 +61,14 @@ export async function installTerminalController(ctx, settings, provider, options
61
61
  settings: () => settings.get().terminalEnhancement,
62
62
  ...(options.platform === undefined ? {} : { platform: options.platform }),
63
63
  ...(options.resolveWorkspaceRoot === undefined ? {} : { resolveWorkspaceRoot: options.resolveWorkspaceRoot }),
64
+ ...(options.registerWorkspaceRoot === undefined ? {} : { registerWorkspaceRoot: options.registerWorkspaceRoot }),
64
65
  };
65
66
  if (!enhancedEnabled) {
66
67
  return createController(ctx, { enhancedEnabled: false, ...common });
67
68
  }
68
69
  const documentPath = provider.documentPath;
69
70
  if (documentPath === undefined) {
70
- throw new Error('终端强化需要文件型 DSH 设置 Provider,以便持久保存 Host ID 和终端映射');
71
+ throw new Error('终端增强需要文件型 DSH 设置 Provider,以便持久保存 Host ID 和终端映射');
71
72
  }
72
73
  const identity = await (options.resolveIdentity ?? resolveTerminalStartupIdentity)(documentPath);
73
74
  return createController(ctx, {
@@ -30,6 +30,8 @@ export interface CodingNsTerminalControllerOptions {
30
30
  readonly platform?: string;
31
31
  readonly generation?: (agent: DshTerminalAgent, attachmentId: string) => string;
32
32
  readonly workspaceId?: (agent: DshTerminalAgent, cwd: string) => string;
33
+ /** 终端解析出 Workspace 后登记 Host 侧可信根目录,供调试服务复用。 */
34
+ readonly registerWorkspaceRoot?: (workspaceId: string, cwd: string) => void;
33
35
  /** 基线模式固定使用进程内 PTY;强化模式再按平台选择持久 backend。 */
34
36
  readonly runtimeType?: (profileId: Exclude<TerminalShellProfileId, 'system'>, platform: string) => CodingNsTerminalRuntimeType;
35
37
  readonly detectShells?: () => readonly DetectedTerminalShell[];
@@ -38,7 +40,7 @@ export interface CodingNsTerminalControllerOptions {
38
40
  readonly maxCols?: number;
39
41
  readonly maxRows?: number;
40
42
  }
41
- /** 与 DSH 0.1.6-alpha.2 `remote.terminal` 完全同名、同方法的 Host controller。 */
43
+ /** Codingns4DSH 自有终端 Host controller,避免与 DSH 官方 `remote.terminal` 冲突。 */
42
44
  export declare class CodingNsTerminalController extends TypertRemoteService {
43
45
  private readonly options;
44
46
  static inject: string[];
@@ -68,8 +70,13 @@ export declare class CodingNsTerminalController extends TypertRemoteService {
68
70
  private scope;
69
71
  private rememberWorkspace;
70
72
  /**
71
- * Workspace Registry 是跨会话的稳定身份。只有找不到正式工作区时才回退到
72
- * 插件提供的 cwd 规则,避免把同一工作区的不同 Session 拆成多个终端集合。
73
+ * list/retain 的 wire 只有 sessionId,可能早于 agent-scoped environment 到达。
74
+ * 这时仍从 Host 侧 Registry 解析工作区,避免暂时缺少缓存就退回会话列表。
75
+ */
76
+ private workspaceForSession;
77
+ /**
78
+ * Workspace Registry 是跨会话的稳定身份;找不到正式工作区时回退到会话身份,
79
+ * 避免旧版 DSH 把 cwd 误当成跨会话的工作区。
73
80
  */
74
81
  private workspaceId;
75
82
  private identity;
@@ -35,7 +35,8 @@ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn,
35
35
  import { Remote, RemoteError, TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
36
36
  import { detectTerminalShells, resolveTerminalShell, } from './shell-detection.js';
37
37
  import { CodingNsTerminalService, TerminalServiceError } from './terminal-service.js';
38
- /** 与 DSH 0.1.6-alpha.2 `remote.terminal` 完全同名、同方法的 Host controller。 */
38
+ import { debugInfo, debugWarn } from '../../shared/debug.js';
39
+ /** Codingns4DSH 自有终端 Host controller,避免与 DSH 官方 `remote.terminal` 冲突。 */
39
40
  let CodingNsTerminalController = (() => {
40
41
  let _classSuper = TypertRemoteService;
41
42
  let _instanceExtraInitializers = [];
@@ -87,7 +88,7 @@ let CodingNsTerminalController = (() => {
87
88
  /** list/retain 的官方 wire 只有 sessionId;这里把它解析到工作区后再查持久终端。 */
88
89
  sessionWorkspaces = new Map();
89
90
  constructor(ctx, options) {
90
- super(ctx, 'terminalController', { namespace: 'terminal' });
91
+ super(ctx, 'terminalController', { namespace: 'codingnsTerminal' });
91
92
  this.options = options;
92
93
  this.platform = options.platform ?? process.platform;
93
94
  this.detectShells = options.detectShells ?? (() => detectTerminalShells({ platform: this.platform }));
@@ -100,9 +101,18 @@ let CodingNsTerminalController = (() => {
100
101
  environment(agent, signal) {
101
102
  signal.throwIfAborted();
102
103
  const workspaceId = this.rememberWorkspace(agent);
103
- return {
104
+ debugInfo('codingns4dsh: terminal environment', {
105
+ sessionId: agent.id,
104
106
  cwd: this.cwd(agent),
107
+ bindingScope: this.bindingScope,
105
108
  workspaceId,
109
+ wireWorkspaceId: isSessionWorkspaceId(workspaceId) ? undefined : workspaceId,
110
+ });
111
+ return {
112
+ cwd: this.cwd(agent),
113
+ // 旧版 DSH 没有 Workspace Registry;不要把 cwd 伪装成稳定 Workspace ID,
114
+ // 否则旧版 Client 会把同目录的不同会话错误合并。
115
+ ...(isSessionWorkspaceId(workspaceId) ? {} : { workspaceId }),
106
116
  maxInputBytes: this.maxInputBytes,
107
117
  maxCols: this.maxCols,
108
118
  maxRows: this.maxRows,
@@ -123,14 +133,27 @@ let CodingNsTerminalController = (() => {
123
133
  return ordered.map(shellOption);
124
134
  }
125
135
  list(sessionId) {
126
- const workspaceId = this.sessionWorkspaces.get(sessionId);
127
- return [...this.options.service.listSession(this.options.hostId, sessionId, workspaceId)];
136
+ const workspaceId = this.workspaceForSession(sessionId);
137
+ const result = [...this.options.service.listSession(this.options.hostId, sessionId, workspaceId)];
138
+ debugInfo('codingns4dsh: terminal list', {
139
+ sessionId,
140
+ workspaceId,
141
+ registryResolved: workspaceId !== undefined && !isSessionWorkspaceId(workspaceId),
142
+ terminalIds: result.map((terminal) => terminal.id),
143
+ });
144
+ return result;
128
145
  }
129
146
  async create(agent, request, signal) {
130
147
  signal.throwIfAborted();
131
148
  const scope = this.scope(agent);
132
149
  this.rememberWorkspace(agent);
133
150
  const existing = this.options.service.list(scope).find((terminal) => terminal.id === request.id);
151
+ debugInfo('codingns4dsh: terminal create', {
152
+ sessionId: agent.id,
153
+ terminalId: request.id,
154
+ scope,
155
+ existing: existing?.id ?? null,
156
+ });
134
157
  if (existing !== undefined)
135
158
  return existing;
136
159
  if (this.options.service.list(scope).length >= this.maxTerminals) {
@@ -155,7 +178,7 @@ let CodingNsTerminalController = (() => {
155
178
  }
156
179
  retain(sessionId, id, signal) {
157
180
  try {
158
- const identity = this.options.service.findIdentity(this.options.hostId, sessionId, id, this.sessionWorkspaces.get(sessionId));
181
+ const identity = this.options.service.findIdentity(this.options.hostId, sessionId, id, this.workspaceForSession(sessionId));
159
182
  return translateTerminalStream(this.options.service.retain(identity, signal));
160
183
  }
161
184
  catch (error) {
@@ -208,10 +231,18 @@ let CodingNsTerminalController = (() => {
208
231
  async close(agent, id) {
209
232
  try {
210
233
  const identity = this.optionalIdentity(agent, id);
211
- if (identity !== undefined)
234
+ debugInfo('codingns4dsh: terminal close entered', {
235
+ sessionId: agent.id,
236
+ terminalId: id,
237
+ identity: identity ?? null,
238
+ });
239
+ if (identity !== undefined) {
212
240
  await this.options.service.close(identity);
241
+ debugInfo('codingns4dsh: terminal close success', { sessionId: agent.id, terminalId: id, identity });
242
+ }
213
243
  }
214
244
  catch (error) {
245
+ debugWarn('codingns4dsh: terminal close failed', { sessionId: agent.id, terminalId: id, error: errorMessage(error) });
215
246
  throw remoteTerminalError(error);
216
247
  }
217
248
  }
@@ -246,26 +277,75 @@ let CodingNsTerminalController = (() => {
246
277
  return workspaceId;
247
278
  }
248
279
  /**
249
- * Workspace Registry 是跨会话的稳定身份。只有找不到正式工作区时才回退到
250
- * 插件提供的 cwd 规则,避免把同一工作区的不同 Session 拆成多个终端集合。
280
+ * list/retain 的 wire 只有 sessionId,可能早于 agent-scoped environment 到达。
281
+ * 这时仍从 Host 侧 Registry 解析工作区,避免暂时缺少缓存就退回会话列表。
282
+ */
283
+ workspaceForSession(sessionId) {
284
+ const cached = this.sessionWorkspaces.get(sessionId);
285
+ if (cached !== undefined) {
286
+ debugInfo('codingns4dsh: terminal workspace lookup', { sessionId, source: 'cache', workspaceId: cached });
287
+ return cached;
288
+ }
289
+ if (this.bindingScope === 'session') {
290
+ const fallback = `session:${sessionId}`;
291
+ debugInfo('codingns4dsh: terminal workspace lookup', { sessionId, source: 'binding-scope-session', workspaceId: fallback });
292
+ return fallback;
293
+ }
294
+ try {
295
+ const registry = this.ctx.get('workspaceRegistry');
296
+ if (registry === undefined) {
297
+ debugWarn('codingns4dsh: terminal workspace lookup unavailable', { sessionId, reason: 'registry-undefined' });
298
+ return undefined;
299
+ }
300
+ const entries = registry.list();
301
+ const workspace = entries.find((entry) => entry.sessionIds.includes(sessionId));
302
+ if (workspace === undefined) {
303
+ debugWarn('codingns4dsh: terminal workspace lookup miss', { sessionId, registryCount: entries.length });
304
+ return undefined;
305
+ }
306
+ this.sessionWorkspaces.set(sessionId, workspace.id);
307
+ debugInfo('codingns4dsh: terminal workspace lookup', { sessionId, source: 'registry', workspaceId: workspace.id, registryCount: entries.length });
308
+ return workspace.id;
309
+ }
310
+ catch (error) {
311
+ debugWarn('codingns4dsh: terminal workspace lookup failed', { sessionId, error: errorMessage(error) });
312
+ return undefined;
313
+ }
314
+ }
315
+ /**
316
+ * Workspace Registry 是跨会话的稳定身份;找不到正式工作区时回退到会话身份,
317
+ * 避免旧版 DSH 把 cwd 误当成跨会话的工作区。
251
318
  */
252
319
  workspaceId(agent, cwd) {
253
- if (this.bindingScope === 'session')
254
- return `session:${agent.id}`;
320
+ if (this.bindingScope === 'session') {
321
+ const value = `session:${agent.id}`;
322
+ debugInfo('codingns4dsh: terminal workspace identity', { sessionId: agent.id, cwd, source: 'binding-scope-session', workspaceId: value });
323
+ return value;
324
+ }
255
325
  // Cordis 未注入可选服务时直接读 ctx.workspaceRegistry 会抛出 "without inject";
256
326
  // 通过 get 探测是官方允许的可选服务读取方式。
257
327
  const registry = this.ctx.get('workspaceRegistry');
258
328
  if (registry !== undefined) {
259
329
  try {
260
- const workspace = registry.list().find((entry) => entry.sessionIds.includes(agent.id));
261
- if (workspace !== undefined)
330
+ const entries = registry.list();
331
+ const workspace = entries.find((entry) => entry.sessionIds.includes(agent.id));
332
+ if (workspace !== undefined) {
333
+ this.options.registerWorkspaceRoot?.(workspace.id, cwd);
334
+ debugInfo('codingns4dsh: terminal workspace identity', { sessionId: agent.id, cwd, source: 'registry', workspaceId: workspace.id, registryCount: entries.length });
262
335
  return workspace.id;
336
+ }
337
+ debugWarn('codingns4dsh: terminal workspace identity miss', { sessionId: agent.id, cwd, registryCount: entries.length });
263
338
  }
264
- catch {
339
+ catch (error) {
265
340
  // Workspace Registry 尚未完成启动时继续使用兼容回退,不能让终端功能阻塞 DSH。
341
+ debugWarn('codingns4dsh: terminal workspace identity lookup failed', { sessionId: agent.id, cwd, error: errorMessage(error) });
266
342
  }
267
343
  }
268
- return this.options.workspaceId?.(agent, cwd) ?? cwd;
344
+ // 没有正式 Registry 时只能保证当前会话隔离。options.workspaceId 保留在
345
+ // 接口中供旧调用方编译兼容,但不能把 cwd 当作跨会话身份。
346
+ const value = `session:${agent.id}`;
347
+ debugWarn('codingns4dsh: terminal workspace identity fallback', { sessionId: agent.id, cwd, reason: registry === undefined ? 'registry-undefined' : 'registry-miss-or-not-ready', workspaceId: value });
348
+ return value;
269
349
  }
270
350
  identity(agent, terminalId) {
271
351
  return { ...this.scope(agent), terminalId };
@@ -283,6 +363,9 @@ let CodingNsTerminalController = (() => {
283
363
  };
284
364
  })();
285
365
  export { CodingNsTerminalController };
366
+ function isSessionWorkspaceId(value) {
367
+ return value.startsWith('session:');
368
+ }
286
369
  function shellOption(shell) {
287
370
  return { path: shell.path, name: shell.displayName, args: shellArgs(shell.profileId) };
288
371
  }
@@ -313,6 +396,9 @@ function remoteTerminalError(error) {
313
396
  }
314
397
  return new RemoteError('terminal/unavailable', error.message, {});
315
398
  }
399
+ function errorMessage(error) {
400
+ return error instanceof Error ? error.message : String(error);
401
+ }
316
402
  async function* translateTerminalStream(stream) {
317
403
  try {
318
404
  yield* stream;
@@ -26,7 +26,9 @@ export class TerminalProcessService {
26
26
  args: [...(input.args ?? [])],
27
27
  env: { ...(input.env ?? {}) },
28
28
  shell: { ...input.shell, args: [...input.shell.args] },
29
- runtimeType: input.runtimeType,
29
+ // 配置可能来自 tmux 不可用时的旧版本;Host 以当前实际注册的 backend 为准,
30
+ // 保证已有调试配置不会因为运行模式切换而彻底无法启动。
31
+ runtimeType: this.options.terminalService.resolveRuntimeType(input.runtimeType),
30
32
  runtimeMode: 'pty',
31
33
  revision: (current?.revision ?? 0) + 1,
32
34
  createdAt: current?.createdAt ?? timestamp,
@@ -41,6 +41,8 @@ export declare class CodingNsTerminalService {
41
41
  private initialized;
42
42
  constructor(store: CodingNsTerminalStore, runtimes: TerminalRuntimeManager, now?: () => Date);
43
43
  initialize(): Promise<void>;
44
+ supportsRuntimeType(runtimeType: CodingNsTerminalRuntimeType): boolean;
45
+ resolveRuntimeType(runtimeType: CodingNsTerminalRuntimeType): CodingNsTerminalRuntimeType;
44
46
  list(scope: TerminalOwnerScope): readonly CodingNsWebTerminalInfo[];
45
47
  /** 兼容旧调用名;真正的持久归属只按 Host + workspace 查询。 */
46
48
  listSession(hostId: string, dshSessionId: string, workspaceId?: string): readonly CodingNsWebTerminalInfo[];
@@ -25,6 +25,16 @@ export class CodingNsTerminalService {
25
25
  await this.store.load();
26
26
  this.initialized = true;
27
27
  }
28
+ supportsRuntimeType(runtimeType) {
29
+ return this.runtimes.supports(runtimeType);
30
+ }
31
+ resolveRuntimeType(runtimeType) {
32
+ if (this.runtimes.supports(runtimeType))
33
+ return runtimeType;
34
+ if (this.runtimes.supports('local-pty'))
35
+ return 'local-pty';
36
+ return runtimeType;
37
+ }
28
38
  list(scope) {
29
39
  this.requireInitialized();
30
40
  return this.store.list(scope)
@@ -1,10 +1,11 @@
1
1
  /** Host 入口是包根导出;共享契约通过显式子路径另行提供。 */
2
2
  import { apply as hostApply } from './host/index.js';
3
3
  /** Cordis Bundle 标准插件名称。 */
4
- export declare const name = "codingns4dsh";
4
+ export declare const name = "@jingyi0605/codingns4dsh";
5
+ /** DSH 0.1.7 原生配置入口;Host-only 的 cliSessions 已标记为 volatile。 */
6
+ export { CodingNsConfigSchema as Config } from './host/settings.js';
5
7
  /** Host Cordis 入口。 */
6
8
  export declare const apply: typeof hostApply;
7
- export default hostApply;
8
9
  export { createCodingNsRpcHandler, createCodingNsSettingsRpcHandler, registerCodingNsRpc } from './host/rpc.js';
9
10
  export { CodingNsRpcError, CodingNsRpcTable, type CodingNsRpcHandler, type CodingNsRpcTarget, } from './host/rpc-table.js';
10
11
  export { HOST_FEATURES, createAuthFeature, createCliAdaptersFeature, createLanAccessDshFeature, } from './host/features/index.js';
@@ -18,8 +19,11 @@ export type { RemoteDshWebBoot, RemoteDshWebContextOptions } from './client/remo
18
19
  export { createHttpDshH5ControlApi, startDshH5BrowserBootstrap } from './client/dsh-h5-bootstrap.js';
19
20
  export type { DshH5BrowserBootstrapOptions, DshH5BrowserBootstrapResult, DshH5BrowserControlApi } from './client/dsh-h5-bootstrap.js';
20
21
  export { CODINGNS_RPC_CHANNEL } from './shared/contracts/transport.js';
22
+ export { CODINGNS4DSH_DEBUG_ENV, debugInfo, debugWarn, resolveCodingNsDebugEnabled, } from './shared/debug.js';
21
23
  export { CODINGNS_CONTROL_BASE_URL_FIELD, CODINGNS_CONTROL_BASE_URLS_FIELD, CODINGNS_LAN_ACCESS_DSH_FIELD, CODINGNS_MODULES_FIELD, CODINGNS_SETTINGS_NAMESPACE, DEFAULT_CODINGNS_CONTROL_BASE_URL, DEFAULT_CODINGNS_CONTROL_BASE_URLS, DEFAULT_CODINGNS_SETTINGS, enabledFeatureNames, isFeatureEnabled, } from './shared/contracts/config.js';
22
24
  export type * from './shared/index.js';
25
+ export * from './dsh-capabilities/index.js';
26
+ export { dispatchCodingNsRpc, type CodingNsRpcContext, type CodingNsRpcDispatchResult } from './dsh-capabilities/host/connection-rpc-adapter.js';
23
27
  export { FeatureRegistry, FeatureRegistryError, FeatureResourceScopeImpl, } from './features/registry.js';
24
28
  export type { FeatureRegistryErrorCode, FeatureSnapshot, } from './features/registry.js';
25
29
  export { ResourceScopeManager } from './features/resource-scope/index.js';
@@ -1,10 +1,13 @@
1
1
  /** Host 入口是包根导出;共享契约通过显式子路径另行提供。 */
2
2
  import { apply as hostApply } from './host/index.js';
3
3
  /** Cordis Bundle 标准插件名称。 */
4
- export const name = 'codingns4dsh';
4
+ // Bundle 的运行时名称必须与 npm 包名和 dsh.bundle.patch 中的 entry id 保持一致。
5
+ // 包名改为 scoped 后仍导出旧名称,会让 DSH 的 Bundle、ConfigForm 和 Client 处于不同身份。
6
+ export const name = '@jingyi0605/codingns4dsh';
7
+ /** DSH 0.1.7 原生配置入口;Host-only 的 cliSessions 已标记为 volatile。 */
8
+ export { CodingNsConfigSchema as Config } from './host/settings.js';
5
9
  /** Host Cordis 入口。 */
6
10
  export const apply = hostApply;
7
- export default hostApply;
8
11
  export { createCodingNsRpcHandler, createCodingNsSettingsRpcHandler, registerCodingNsRpc } from './host/rpc.js';
9
12
  export { CodingNsRpcError, CodingNsRpcTable, } from './host/rpc-table.js';
10
13
  export { HOST_FEATURES, createAuthFeature, createCliAdaptersFeature, createLanAccessDshFeature, } from './host/features/index.js';
@@ -14,7 +17,10 @@ export { createLocalDshWebRuntimeProvider, createRemoteWebRuntimeFeature, } from
14
17
  export { RemoteDshWebContext } from './client/remote-web-context.js';
15
18
  export { createHttpDshH5ControlApi, startDshH5BrowserBootstrap } from './client/dsh-h5-bootstrap.js';
16
19
  export { CODINGNS_RPC_CHANNEL } from './shared/contracts/transport.js';
20
+ export { CODINGNS4DSH_DEBUG_ENV, debugInfo, debugWarn, resolveCodingNsDebugEnabled, } from './shared/debug.js';
17
21
  export { CODINGNS_CONTROL_BASE_URL_FIELD, CODINGNS_CONTROL_BASE_URLS_FIELD, CODINGNS_LAN_ACCESS_DSH_FIELD, CODINGNS_MODULES_FIELD, CODINGNS_SETTINGS_NAMESPACE, DEFAULT_CODINGNS_CONTROL_BASE_URL, DEFAULT_CODINGNS_CONTROL_BASE_URLS, DEFAULT_CODINGNS_SETTINGS, enabledFeatureNames, isFeatureEnabled, } from './shared/contracts/config.js';
22
+ export * from './dsh-capabilities/index.js';
23
+ export { dispatchCodingNsRpc } from './dsh-capabilities/host/connection-rpc-adapter.js';
18
24
  export { FeatureRegistry, FeatureRegistryError, FeatureResourceScopeImpl, } from './features/registry.js';
19
25
  export { ResourceScopeManager } from './features/resource-scope/index.js';
20
26
  export { CodingNsAuthSession, } from './host/auth-session.js';