dsh-coding-sidebar 1.0.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 (277) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +524 -0
  3. package/cordis.patch.yml +49 -0
  4. package/lib/client-editor.js +48229 -0
  5. package/lib/client-mermaid.js +200745 -0
  6. package/lib/client-registry.js +21867 -0
  7. package/lib/client-terminal.js +9361 -0
  8. package/lib/client.js +21867 -0
  9. package/lib/index.js +4556 -0
  10. package/lib/invariant.js +22 -0
  11. package/lib/types/agent-opens.d.ts +65 -0
  12. package/lib/types/agent-pty.d.ts +226 -0
  13. package/lib/types/browser-probe.d.ts +15 -0
  14. package/lib/types/bundle-route.d.ts +12 -0
  15. package/lib/types/client/BrowserView.d.ts +39 -0
  16. package/lib/types/client/DiffTab.d.ts +6 -0
  17. package/lib/types/client/DiffView.d.ts +51 -0
  18. package/lib/types/client/EditorHost.d.ts +13 -0
  19. package/lib/types/client/FileTree.d.ts +38 -0
  20. package/lib/types/client/FreeWindow.d.ts +29 -0
  21. package/lib/types/client/GitView.d.ts +10 -0
  22. package/lib/types/client/MarkdownHtml.d.ts +32 -0
  23. package/lib/types/client/OrphanedTab.d.ts +11 -0
  24. package/lib/types/client/PdfView.d.ts +6 -0
  25. package/lib/types/client/RenderBoundary.d.ts +32 -0
  26. package/lib/types/client/SandboxStatusBar.d.ts +10 -0
  27. package/lib/types/client/SideCardSection.d.ts +74 -0
  28. package/lib/types/client/SideChatView.d.ts +16 -0
  29. package/lib/types/client/Sidebar.d.ts +6 -0
  30. package/lib/types/client/SubagentView.d.ts +16 -0
  31. package/lib/types/client/TabBar.d.ts +54 -0
  32. package/lib/types/client/TerminalView.d.ts +24 -0
  33. package/lib/types/client/TextEditor.d.ts +10 -0
  34. package/lib/types/client/TreePanel.d.ts +24 -0
  35. package/lib/types/client/UploadOverlay.d.ts +20 -0
  36. package/lib/types/client/add-plugin-modal.d.ts +15 -0
  37. package/lib/types/client/api.d.ts +275 -0
  38. package/lib/types/client/binary-download.d.ts +12 -0
  39. package/lib/types/client/breakpoints.d.ts +17 -0
  40. package/lib/types/client/browser.d.ts +60 -0
  41. package/lib/types/client/builtins/index.d.ts +18 -0
  42. package/lib/types/client/builtins/tabs.d.ts +11 -0
  43. package/lib/types/client/builtins/viewers.d.ts +3 -0
  44. package/lib/types/client/chunk-loader.d.ts +131 -0
  45. package/lib/types/client/chunks/editor.d.ts +9 -0
  46. package/lib/types/client/chunks/mermaid.d.ts +10 -0
  47. package/lib/types/client/chunks/terminal.d.ts +9 -0
  48. package/lib/types/client/cm-themes.d.ts +24 -0
  49. package/lib/types/client/conversation-draft.d.ts +14 -0
  50. package/lib/types/client/desktop-env.d.ts +35 -0
  51. package/lib/types/client/editor-load.d.ts +66 -0
  52. package/lib/types/client/frame-batcher.d.ts +24 -0
  53. package/lib/types/client/icons.d.ts +59 -0
  54. package/lib/types/client/image-types.d.ts +3 -0
  55. package/lib/types/client/ime-guard.d.ts +36 -0
  56. package/lib/types/client/index.d.ts +25 -0
  57. package/lib/types/client/intercept.d.ts +46 -0
  58. package/lib/types/client/lang.d.ts +14 -0
  59. package/lib/types/client/layout-push.d.ts +15 -0
  60. package/lib/types/client/lazy-chunk.d.ts +25 -0
  61. package/lib/types/client/link-intercept.d.ts +42 -0
  62. package/lib/types/client/locales-ar.d.ts +18 -0
  63. package/lib/types/client/locales-de.d.ts +4 -0
  64. package/lib/types/client/locales-fr.d.ts +10 -0
  65. package/lib/types/client/locales-hi.d.ts +17 -0
  66. package/lib/types/client/locales-id.d.ts +15 -0
  67. package/lib/types/client/locales-it.d.ts +8 -0
  68. package/lib/types/client/locales-ja.d.ts +17 -0
  69. package/lib/types/client/locales-ko.d.ts +9 -0
  70. package/lib/types/client/locales-nl.d.ts +16 -0
  71. package/lib/types/client/locales-pl.d.ts +19 -0
  72. package/lib/types/client/locales-pt.d.ts +1 -0
  73. package/lib/types/client/locales-ru.d.ts +13 -0
  74. package/lib/types/client/locales-sv.d.ts +1 -0
  75. package/lib/types/client/locales-th.d.ts +17 -0
  76. package/lib/types/client/locales-tr.d.ts +17 -0
  77. package/lib/types/client/locales-vi.d.ts +17 -0
  78. package/lib/types/client/locales-zh-HK.d.ts +32 -0
  79. package/lib/types/client/locales-zh-MO.d.ts +32 -0
  80. package/lib/types/client/locales-zh-TW.d.ts +32 -0
  81. package/lib/types/client/locales.d.ts +452 -0
  82. package/lib/types/client/markdown-html.d.ts +96 -0
  83. package/lib/types/client/markdown-images.d.ts +45 -0
  84. package/lib/types/client/markdown-labels.d.ts +38 -0
  85. package/lib/types/client/md-toc.d.ts +4 -0
  86. package/lib/types/client/mermaid-blocks.d.ts +47 -0
  87. package/lib/types/client/mermaid-sanitize.d.ts +2 -0
  88. package/lib/types/client/mermaid.d.ts +12 -0
  89. package/lib/types/client/open-when-sized.d.ts +20 -0
  90. package/lib/types/client/open-with-settings.d.ts +4 -0
  91. package/lib/types/client/open-with.d.ts +87 -0
  92. package/lib/types/client/openpath-intercept.d.ts +85 -0
  93. package/lib/types/client/paths.d.ts +43 -0
  94. package/lib/types/client/pdf-types.d.ts +2 -0
  95. package/lib/types/client/pinned.d.ts +86 -0
  96. package/lib/types/client/plugin-settings.d.ts +8 -0
  97. package/lib/types/client/plugins-shared.d.ts +27 -0
  98. package/lib/types/client/plugins-tabs.d.ts +3 -0
  99. package/lib/types/client/plugins-viewers.d.ts +3 -0
  100. package/lib/types/client/prefs.d.ts +41 -0
  101. package/lib/types/client/produced-files.d.ts +29 -0
  102. package/lib/types/client/selection-payload.d.ts +27 -0
  103. package/lib/types/client/service.d.ts +439 -0
  104. package/lib/types/client/settings-nav-icon.d.ts +19 -0
  105. package/lib/types/client/shell-presets.d.ts +48 -0
  106. package/lib/types/client/sidechat-transcript.d.ts +103 -0
  107. package/lib/types/client/split-pane.d.ts +36 -0
  108. package/lib/types/client/state.d.ts +432 -0
  109. package/lib/types/client/subagent-detect.d.ts +54 -0
  110. package/lib/types/client/subagent-jobs.d.ts +63 -0
  111. package/lib/types/client/tab-content-memo.d.ts +40 -0
  112. package/lib/types/client/terminal-font.d.ts +78 -0
  113. package/lib/types/client/terminal-links.d.ts +119 -0
  114. package/lib/types/client/theme.d.ts +45 -0
  115. package/lib/types/client/titlebar-strip.d.ts +23 -0
  116. package/lib/types/client/upload.d.ts +69 -0
  117. package/lib/types/client/wco.d.ts +47 -0
  118. package/lib/types/config.d.ts +64 -0
  119. package/lib/types/context-types.d.ts +605 -0
  120. package/lib/types/fs-operations.d.ts +28 -0
  121. package/lib/types/fs-search.d.ts +24 -0
  122. package/lib/types/fs-tree.d.ts +51 -0
  123. package/lib/types/git.d.ts +124 -0
  124. package/lib/types/html-route.d.ts +59 -0
  125. package/lib/types/index.d.ts +47 -0
  126. package/lib/types/invariant.d.ts +15 -0
  127. package/lib/types/jobs-routes.d.ts +45 -0
  128. package/lib/types/open-external.d.ts +24 -0
  129. package/lib/types/path-security.d.ts +20 -0
  130. package/lib/types/prefs-shared.d.ts +236 -0
  131. package/lib/types/pty-deps.d.ts +78 -0
  132. package/lib/types/pty-manager.d.ts +168 -0
  133. package/lib/types/sidechat-core.d.ts +172 -0
  134. package/lib/types/sidechat-routes.d.ts +30 -0
  135. package/lib/types/subagent-activity.d.ts +44 -0
  136. package/lib/types/subagent-live-route.d.ts +44 -0
  137. package/lib/types/tools.d.ts +34 -0
  138. package/lib/types/trust-fence.d.ts +24 -0
  139. package/lib/types/wire.d.ts +38 -0
  140. package/package.json +172 -0
  141. package/scripts/install.ps1 +306 -0
  142. package/scripts/install.sh +287 -0
  143. package/src/agent-opens.ts +265 -0
  144. package/src/agent-pty.ts +527 -0
  145. package/src/browser-probe.ts +26 -0
  146. package/src/bundle-route.ts +129 -0
  147. package/src/client/BrowserView.tsx +289 -0
  148. package/src/client/DiffTab.tsx +114 -0
  149. package/src/client/DiffView.tsx +305 -0
  150. package/src/client/EditorHost.tsx +558 -0
  151. package/src/client/FileTree.tsx +669 -0
  152. package/src/client/FreeWindow.tsx +337 -0
  153. package/src/client/GitView.tsx +717 -0
  154. package/src/client/MarkdownHtml.tsx +296 -0
  155. package/src/client/OrphanedTab.tsx +27 -0
  156. package/src/client/PdfView.tsx +110 -0
  157. package/src/client/RenderBoundary.tsx +49 -0
  158. package/src/client/SandboxStatusBar.tsx +60 -0
  159. package/src/client/SideCardSection.module.css +960 -0
  160. package/src/client/SideCardSection.tsx +1163 -0
  161. package/src/client/SideChatView.module.css +437 -0
  162. package/src/client/SideChatView.tsx +645 -0
  163. package/src/client/Sidebar.tsx +1370 -0
  164. package/src/client/SubagentView.module.css +547 -0
  165. package/src/client/SubagentView.tsx +883 -0
  166. package/src/client/TabBar.tsx +365 -0
  167. package/src/client/TerminalView.tsx +424 -0
  168. package/src/client/TextEditor.tsx +468 -0
  169. package/src/client/TreePanel.tsx +275 -0
  170. package/src/client/UploadOverlay.tsx +62 -0
  171. package/src/client/add-plugin-modal.tsx +199 -0
  172. package/src/client/api.ts +357 -0
  173. package/src/client/binary-download.tsx +23 -0
  174. package/src/client/breakpoints.ts +61 -0
  175. package/src/client/browser.ts +167 -0
  176. package/src/client/builtins/index.ts +37 -0
  177. package/src/client/builtins/tabs.tsx +340 -0
  178. package/src/client/builtins/viewers.tsx +125 -0
  179. package/src/client/chunk-loader.ts +358 -0
  180. package/src/client/chunks/editor.tsx +9 -0
  181. package/src/client/chunks/mermaid.tsx +10 -0
  182. package/src/client/chunks/terminal.tsx +9 -0
  183. package/src/client/cm-themes.ts +129 -0
  184. package/src/client/conversation-draft.ts +29 -0
  185. package/src/client/css-modules.d.ts +5 -0
  186. package/src/client/desktop-env.ts +72 -0
  187. package/src/client/editor-load.ts +92 -0
  188. package/src/client/frame-batcher.ts +56 -0
  189. package/src/client/icons.tsx +152 -0
  190. package/src/client/image-types.ts +8 -0
  191. package/src/client/ime-guard.ts +47 -0
  192. package/src/client/index.tsx +427 -0
  193. package/src/client/intercept.tsx +188 -0
  194. package/src/client/lang.ts +225 -0
  195. package/src/client/layout-push.ts +24 -0
  196. package/src/client/layout.css +90 -0
  197. package/src/client/lazy-chunk.tsx +89 -0
  198. package/src/client/link-intercept.ts +73 -0
  199. package/src/client/locales-ar.ts +368 -0
  200. package/src/client/locales-de.ts +353 -0
  201. package/src/client/locales-fr.ts +360 -0
  202. package/src/client/locales-hi.ts +367 -0
  203. package/src/client/locales-id.ts +365 -0
  204. package/src/client/locales-it.ts +358 -0
  205. package/src/client/locales-ja.ts +367 -0
  206. package/src/client/locales-ko.ts +359 -0
  207. package/src/client/locales-nl.ts +365 -0
  208. package/src/client/locales-pl.ts +369 -0
  209. package/src/client/locales-pt.ts +350 -0
  210. package/src/client/locales-ru.ts +365 -0
  211. package/src/client/locales-sv.ts +350 -0
  212. package/src/client/locales-th.ts +367 -0
  213. package/src/client/locales-tr.ts +367 -0
  214. package/src/client/locales-vi.ts +367 -0
  215. package/src/client/locales-zh-HK.ts +382 -0
  216. package/src/client/locales-zh-MO.ts +382 -0
  217. package/src/client/locales-zh-TW.ts +382 -0
  218. package/src/client/locales.ts +894 -0
  219. package/src/client/markdown-html.ts +331 -0
  220. package/src/client/markdown-images.ts +137 -0
  221. package/src/client/markdown-labels.tsx +52 -0
  222. package/src/client/md-toc.tsx +127 -0
  223. package/src/client/mermaid-blocks.ts +110 -0
  224. package/src/client/mermaid-sanitize.ts +93 -0
  225. package/src/client/mermaid.tsx +406 -0
  226. package/src/client/open-when-sized.ts +43 -0
  227. package/src/client/open-with-settings.tsx +135 -0
  228. package/src/client/open-with.ts +221 -0
  229. package/src/client/openpath-intercept.ts +143 -0
  230. package/src/client/paths.ts +63 -0
  231. package/src/client/pdf-types.ts +4 -0
  232. package/src/client/pinned.ts +183 -0
  233. package/src/client/plugin-settings.ts +43 -0
  234. package/src/client/plugins-shared.ts +29 -0
  235. package/src/client/plugins-tabs.ts +96 -0
  236. package/src/client/plugins-viewers.ts +30 -0
  237. package/src/client/prefs.ts +210 -0
  238. package/src/client/produced-files.ts +120 -0
  239. package/src/client/selection-payload.ts +86 -0
  240. package/src/client/service.ts +859 -0
  241. package/src/client/settings-nav-icon.ts +45 -0
  242. package/src/client/shell-presets.ts +83 -0
  243. package/src/client/sidebar.module.css +2788 -0
  244. package/src/client/sidechat-transcript.ts +321 -0
  245. package/src/client/split-pane.tsx +331 -0
  246. package/src/client/state.ts +1497 -0
  247. package/src/client/subagent-detect.ts +137 -0
  248. package/src/client/subagent-jobs.ts +161 -0
  249. package/src/client/tab-content-memo.ts +55 -0
  250. package/src/client/terminal-font.ts +224 -0
  251. package/src/client/terminal-links.ts +194 -0
  252. package/src/client/theme.ts +110 -0
  253. package/src/client/titlebar-strip.ts +37 -0
  254. package/src/client/upload.ts +187 -0
  255. package/src/client/wco.ts +120 -0
  256. package/src/config.ts +154 -0
  257. package/src/context-types.ts +611 -0
  258. package/src/fs-operations.ts +95 -0
  259. package/src/fs-search.ts +113 -0
  260. package/src/fs-tree.ts +158 -0
  261. package/src/git.ts +446 -0
  262. package/src/html-route.ts +106 -0
  263. package/src/index.ts +1291 -0
  264. package/src/invariant.ts +32 -0
  265. package/src/jobs-routes.ts +257 -0
  266. package/src/open-external.ts +90 -0
  267. package/src/path-security.ts +75 -0
  268. package/src/prefs-shared.ts +280 -0
  269. package/src/pty-deps.ts +240 -0
  270. package/src/pty-manager.ts +376 -0
  271. package/src/sidechat-core.ts +468 -0
  272. package/src/sidechat-routes.ts +344 -0
  273. package/src/subagent-activity.ts +91 -0
  274. package/src/subagent-live-route.ts +93 -0
  275. package/src/tools.ts +482 -0
  276. package/src/trust-fence.ts +84 -0
  277. package/src/wire.ts +100 -0
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Syntax highlighting for the file editor: extension → CodeMirror language
3
+ * mapping. The key derivation is pure and unit-tested; the factories pull in
4
+ * the CodeMirror language packages (bundled into the client).
5
+ */
6
+ import { Language, LanguageSupport, StreamLanguage } from '@codemirror/language'
7
+ import { javascript, jsxLanguage, typescriptLanguage, tsxLanguage } from '@codemirror/lang-javascript'
8
+ import { json } from '@codemirror/lang-json'
9
+ import { markdown } from '@codemirror/lang-markdown'
10
+ import { python } from '@codemirror/lang-python'
11
+ import { html } from '@codemirror/lang-html'
12
+ import { css, cssLanguage } from '@codemirror/lang-css'
13
+ import { xml } from '@codemirror/lang-xml'
14
+ import { yaml } from '@codemirror/lang-yaml'
15
+ import { sql } from '@codemirror/lang-sql'
16
+ import { java } from '@codemirror/lang-java'
17
+ import { cpp } from '@codemirror/lang-cpp'
18
+ import { rust } from '@codemirror/lang-rust'
19
+ import { go } from '@codemirror/lang-go'
20
+ import { php } from '@codemirror/lang-php'
21
+ import { vue } from '@codemirror/lang-vue'
22
+ import { shell } from '@codemirror/legacy-modes/mode/shell'
23
+ import { toml } from '@codemirror/legacy-modes/mode/toml'
24
+ import { nginx } from '@codemirror/legacy-modes/mode/nginx'
25
+ import { dockerFile } from '@codemirror/legacy-modes/mode/dockerfile'
26
+ import { properties } from '@codemirror/legacy-modes/mode/properties'
27
+ import { csharp, kotlin, dart, scala, objectiveCpp } from '@codemirror/legacy-modes/mode/clike'
28
+ import { swift } from '@codemirror/legacy-modes/mode/swift'
29
+ import { sCSS, less } from '@codemirror/legacy-modes/mode/css'
30
+ import { sass } from '@codemirror/legacy-modes/mode/sass'
31
+ import { stylus } from '@codemirror/legacy-modes/mode/stylus'
32
+ import { ruby } from '@codemirror/legacy-modes/mode/ruby'
33
+ import { lua } from '@codemirror/legacy-modes/mode/lua'
34
+ import { perl } from '@codemirror/legacy-modes/mode/perl'
35
+ import { r } from '@codemirror/legacy-modes/mode/r'
36
+ import { groovy } from '@codemirror/legacy-modes/mode/groovy'
37
+ import { powerShell } from '@codemirror/legacy-modes/mode/powershell'
38
+ import { diff } from '@codemirror/legacy-modes/mode/diff'
39
+ import { protobuf } from '@codemirror/legacy-modes/mode/protobuf'
40
+ import { cmake } from '@codemirror/legacy-modes/mode/cmake'
41
+ import { pug } from '@codemirror/legacy-modes/mode/pug'
42
+ import { tcl } from '@codemirror/legacy-modes/mode/tcl'
43
+ import { haskell } from '@codemirror/legacy-modes/mode/haskell'
44
+ import { clojure } from '@codemirror/legacy-modes/mode/clojure'
45
+ import { erlang } from '@codemirror/legacy-modes/mode/erlang'
46
+ import { julia } from '@codemirror/legacy-modes/mode/julia'
47
+ import { pascal } from '@codemirror/legacy-modes/mode/pascal'
48
+ import { vb } from '@codemirror/legacy-modes/mode/vb'
49
+ import { vhdl } from '@codemirror/legacy-modes/mode/vhdl'
50
+ import { stex } from '@codemirror/legacy-modes/mode/stex'
51
+
52
+ /** The lowercased file extension of a path ('' when none). */
53
+ export function extOf(path: string): string {
54
+ const at = path.lastIndexOf('.')
55
+ if (at === -1) return ''
56
+ const base = path.slice(at + 1).toLowerCase()
57
+ return base.includes('/') || base.includes('\\') ? '' : base
58
+ }
59
+
60
+ /** Language key for an extension, or null for plain text. Pure (tested). */
61
+ export function languageKeyForExt(ext: string): string | null {
62
+ switch (ext) {
63
+ case 'js': case 'mjs': case 'cjs': return 'js'
64
+ case 'jsx': return 'jsx'
65
+ case 'ts': case 'mts': case 'cts': return 'ts'
66
+ case 'tsx': return 'tsx'
67
+ case 'json': case 'jsonc': return 'json'
68
+ case 'md': case 'markdown': return 'md'
69
+ case 'py': case 'pyw': return 'python'
70
+ case 'html': case 'htm': return 'html'
71
+ case 'css': return 'css'
72
+ case 'xml': case 'xsl': return 'xml'
73
+ case 'yaml': case 'yml': return 'yaml'
74
+ case 'sql': return 'sql'
75
+ case 'java': return 'java'
76
+ case 'cs': return 'csharp'
77
+ case 'kt': case 'kts': return 'kotlin'
78
+ case 'swift': return 'swift'
79
+ case 'c': case 'h': return 'c'
80
+ case 'cc': case 'cpp': case 'cxx': case 'hpp': case 'hh': case 'hxx': return 'cpp'
81
+ case 'rs': return 'rust'
82
+ case 'go': return 'go'
83
+ case 'php': return 'php'
84
+ case 'sh': case 'bash': case 'zsh': return 'shell'
85
+ case 'toml': return 'toml'
86
+ case 'nginx': case 'conf': return 'nginx'
87
+ case 'dockerfile': case 'docker': return 'dockerfile'
88
+ case 'properties': case 'env': return 'properties'
89
+ case 'vue': return 'vue'
90
+ case 'scss': return 'scss'
91
+ case 'sass': return 'sass'
92
+ case 'less': return 'less'
93
+ case 'styl': return 'stylus'
94
+ case 'rb': return 'ruby'
95
+ case 'lua': return 'lua'
96
+ case 'pl': case 'pm': return 'perl'
97
+ case 'r': return 'r'
98
+ case 'dart': return 'dart'
99
+ case 'scala': case 'sc': return 'scala'
100
+ case 'groovy': return 'groovy'
101
+ case 'ps1': case 'psm1': return 'powershell'
102
+ case 'diff': case 'patch': return 'diff'
103
+ case 'proto': return 'protobuf'
104
+ case 'cmake': return 'cmake'
105
+ case 'pug': return 'pug'
106
+ case 'tcl': return 'tcl'
107
+ case 'hs': return 'haskell'
108
+ case 'clj': case 'cljs': return 'clojure'
109
+ case 'erl': return 'erlang'
110
+ case 'jl': return 'julia'
111
+ case 'pas': return 'pascal'
112
+ case 'vb': return 'vb'
113
+ case 'vhd': return 'vhdl'
114
+ case 'tex': return 'stex'
115
+ case 'mm': return 'objectivecpp'
116
+ // '.v' (Verilog/Coq/V) 与 '.m' (Objective-C/MATLAB) 存在跨语言歧义,
117
+ // 故意不映射——错配高亮比纯文本更误导。
118
+ default: return null
119
+ }
120
+ }
121
+
122
+ /** Per-lang `<style>` parsers for the Vue SFC factory (built once, shared). */
123
+ const VUE_STYLE_PARSERS = {
124
+ scss: StreamLanguage.define(sCSS).parser,
125
+ sass: StreamLanguage.define(sass).parser,
126
+ less: StreamLanguage.define(less).parser,
127
+ stylus: StreamLanguage.define(stylus).parser,
128
+ }
129
+
130
+ const FACTORIES: Record<string, () => Language | LanguageSupport> = {
131
+ js: () => javascript({ jsx: true }),
132
+ jsx: () => javascript({ jsx: true }),
133
+ ts: () => javascript({ typescript: true }),
134
+ tsx: () => javascript({ typescript: true, jsx: true }),
135
+ json: () => json(),
136
+ md: () => markdown(),
137
+ python: () => python(),
138
+ html: () => html(),
139
+ css: () => css(),
140
+ xml: () => xml(),
141
+ yaml: () => yaml(),
142
+ sql: () => sql(),
143
+ java: () => java(),
144
+ csharp: () => StreamLanguage.define(csharp),
145
+ kotlin: () => StreamLanguage.define(kotlin),
146
+ swift: () => StreamLanguage.define(swift),
147
+ c: () => cpp(),
148
+ cpp: () => cpp(),
149
+ rust: () => rust(),
150
+ go: () => go(),
151
+ php: () => php(),
152
+ shell: () => StreamLanguage.define(shell),
153
+ toml: () => StreamLanguage.define(toml),
154
+ nginx: () => StreamLanguage.define(nginx),
155
+ dockerfile: () => StreamLanguage.define(dockerFile),
156
+ properties: () => StreamLanguage.define(properties),
157
+ // Vue SFC: lang-html's default html() base ALREADY parses <script>
158
+ // (no type → JS, type="module" → JS, lang="ts" → TS, JSON/importmap MIME
159
+ // types) and <style> → CSS through its built-in defaultNesting. The
160
+ // explicit entries only ADD what the defaults miss — case-insensitive
161
+ // lang="ts", lang="tsx"/"jsx" (the defaults only recognize the text/jsx &
162
+ // text/typescript-jsx MIME types), and per-lang <style> preprocessor
163
+ // dispatch. Same-tag entries are first-match wins and ours precede the
164
+ // defaults, so the predicates stay narrow: a constant-true entry would
165
+ // shadow the default JSON/importmap script handling and force the CSS
166
+ // parser onto <style lang="stylus">.
167
+ vue: () => vue({
168
+ base: html({
169
+ nestedLanguages: [
170
+ { tag: 'script', attrs: a => (a.lang ?? '').toLowerCase() === 'ts', parser: typescriptLanguage.parser },
171
+ { tag: 'script', attrs: a => (a.lang ?? '').toLowerCase() === 'tsx', parser: tsxLanguage.parser },
172
+ { tag: 'script', attrs: a => (a.lang ?? '').toLowerCase() === 'jsx', parser: jsxLanguage.parser },
173
+ { tag: 'style', attrs: a => (a.lang ?? '').toLowerCase() === 'css', parser: cssLanguage.parser },
174
+ { tag: 'style', attrs: a => (a.lang ?? '').toLowerCase() === 'scss', parser: VUE_STYLE_PARSERS.scss },
175
+ { tag: 'style', attrs: a => (a.lang ?? '').toLowerCase() === 'sass', parser: VUE_STYLE_PARSERS.sass },
176
+ { tag: 'style', attrs: a => (a.lang ?? '').toLowerCase() === 'less', parser: VUE_STYLE_PARSERS.less },
177
+ { tag: 'style', attrs: a => (a.lang ?? '').toLowerCase() === 'stylus', parser: VUE_STYLE_PARSERS.stylus },
178
+ ],
179
+ }),
180
+ }),
181
+ scss: () => StreamLanguage.define(sCSS),
182
+ sass: () => StreamLanguage.define(sass),
183
+ less: () => StreamLanguage.define(less),
184
+ stylus: () => StreamLanguage.define(stylus),
185
+ ruby: () => StreamLanguage.define(ruby),
186
+ lua: () => StreamLanguage.define(lua),
187
+ perl: () => StreamLanguage.define(perl),
188
+ r: () => StreamLanguage.define(r),
189
+ dart: () => StreamLanguage.define(dart),
190
+ scala: () => StreamLanguage.define(scala),
191
+ groovy: () => StreamLanguage.define(groovy),
192
+ powershell: () => StreamLanguage.define(powerShell),
193
+ diff: () => StreamLanguage.define(diff),
194
+ protobuf: () => StreamLanguage.define(protobuf),
195
+ cmake: () => StreamLanguage.define(cmake),
196
+ pug: () => StreamLanguage.define(pug),
197
+ tcl: () => StreamLanguage.define(tcl),
198
+ haskell: () => StreamLanguage.define(haskell),
199
+ clojure: () => StreamLanguage.define(clojure),
200
+ erlang: () => StreamLanguage.define(erlang),
201
+ julia: () => StreamLanguage.define(julia),
202
+ pascal: () => StreamLanguage.define(pascal),
203
+ vb: () => StreamLanguage.define(vb),
204
+ vhdl: () => StreamLanguage.define(vhdl),
205
+ stex: () => StreamLanguage.define(stex),
206
+ objectivecpp: () => StreamLanguage.define(objectiveCpp),
207
+ }
208
+
209
+ /** Every language key the extension table can produce (test seam). */
210
+ export function supportedLanguageKeys(): readonly string[] {
211
+ return Object.keys(FACTORIES)
212
+ }
213
+
214
+ /** The CodeMirror language support for a path, or null for plain text. */
215
+ export function languageForPath(path: string): Language | LanguageSupport | null {
216
+ const key = languageKeyForExt(extOf(path))
217
+ if (key === null) return null
218
+ try {
219
+ return FACTORIES[key]!()
220
+ } catch (error) {
221
+ // A broken factory degrades to plain text, never crashes the editor.
222
+ console.warn(`[dsh-coding-sidebar] language factory "${key}" failed:`, error)
223
+ return null
224
+ }
225
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Width written to `--dsh-sidebar-width`: the app shell gives up this much
3
+ * of the viewport while the sidebar is open (0 while collapsed), so the
4
+ * conversation column (output + composer) is squeezed instead of covered.
5
+ * The value is capped at the viewport so a stale persisted size (e.g.
6
+ * fullscreen on a bigger window) can never crush the app shell to zero.
7
+ */
8
+
9
+ function finiteNonNegative(value: number): number {
10
+ return Number.isFinite(value) ? Math.max(0, value) : 0
11
+ }
12
+
13
+ export interface LayoutPushInput {
14
+ narrow: boolean
15
+ panelOpen: boolean
16
+ width: number
17
+ viewportWidth: number
18
+ }
19
+
20
+ /** Compute the live layout-push width. Narrow drawers float and push 0. */
21
+ export function layoutPushSize(input: LayoutPushInput): number {
22
+ if (input.narrow) return 0
23
+ return input.panelOpen ? Math.min(finiteNonNegative(input.width), finiteNonNegative(input.viewportWidth)) : 0
24
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Layout push: when a panel is open it OCCUPIES the layout instead of
3
+ * floating over it — the app shell (#root, the AppFrame three-column grid)
4
+ * gives up space. Only the center column is flexible (1fr), so the right
5
+ * panel's width squeeze (margin-right on #root) lands exactly on the
6
+ * conversation output and the input bar, like a VSCode sidebar.
7
+ *
8
+ * The width rides `calc(100% - var(...))` instead of a bare margin on a
9
+ * full-width box: some desktop shells (DSH Desktop, #208) set #root to
10
+ * width:100%, where a margin would overflow the viewport additively —
11
+ * the calc keeps the box at exactly 100% minus the push in every shell.
12
+ * Width and margin transition in lockstep (same variable, same duration
13
+ * and easing), so expand/collapse animates the content width exactly as
14
+ * the bare-margin version did.
15
+ *
16
+ * The size rides the CSS variable updated by the Sidebar shell (0 while
17
+ * collapsed); expand/collapse animates the margin and the panel slide on
18
+ * the same theme duration. Drags disable the transition so the layout
19
+ * tracks the pointer.
20
+ */
21
+ #root {
22
+ margin-right: var(--dsh-sidebar-width, 0px);
23
+ width: calc(100% - var(--dsh-sidebar-width, 0px));
24
+ transition:
25
+ margin-right var(--ds-transition-duration-slow) var(--ds-ease-in-out),
26
+ width var(--ds-transition-duration-slow) var(--ds-ease-in-out);
27
+ }
28
+
29
+ /* The AppFrame's center column, anchored by data attributes (see above).
30
+ Composite selector: DSH 0.1.x versions name the center grid item
31
+ `[data-pane="conversation"]`, while rc.8-era shells put a
32
+ `[data-slot="conversation"]` child inside it — both selectors resolve to
33
+ the SAME element on live pages (verified), and keeping both future-proofs
34
+ the rule against a host rename without touching shell-specific markup. */
35
+ #root [data-dsh-frame] > [data-pane="conversation"],
36
+ #root :has(> [data-slot="conversation"]) {
37
+ /* Grid/flex items default to min-height:auto. A long unbreakable token
38
+ (OAuth URL) then grows this column past the viewport and clips the
39
+ composer + left-rail Settings row. min-height:0 lets the cell shrink;
40
+ overflow-wrap lets the token wrap instead of forcing its intrinsic
41
+ size. The host's own descendants remain responsible for scrolling. */
42
+ min-height: 0;
43
+ overflow-wrap: anywhere;
44
+ }
45
+
46
+ /* When the sidebar is collapsed, the toggle button reclaims the top-right
47
+ corner. Push the DSH session header's right padding out so its right-aligned
48
+ utilities (the "Session log" download capsule) yield the corner instead of
49
+ hiding under the button. The header default right-pads 28px; the button
50
+ spans right 10→38px, so 46px clears it with an 8px gap. Anchor on
51
+ the header's slot host wrapper ([data-slot="conversation.session.header"])
52
+ rather than a positional path: DSH 0.1.x nests the header several levels
53
+ under the center column. The Sidebar shell toggles the body attribute with
54
+ the panel open state. */
55
+ body[data-dsh-sidebar-collapsed] [data-slot="conversation.session.header"] > header {
56
+ padding-right: 46px;
57
+ }
58
+
59
+ body[data-dsh-sidebar-dragging] #root,
60
+ body[data-dsh-sidebar-dragging] #root [data-dsh-frame] > [data-pane="conversation"],
61
+ body[data-dsh-sidebar-dragging] #root :has(> [data-slot="conversation"]) {
62
+ transition: none;
63
+ }
64
+
65
+ /* DSH 0.1.x gives external settings sections a generic gear and exposes no
66
+ icon field in the settings.section contract. settings-nav-icon.ts marks
67
+ only this plugin's localized row; render the requested Lucide
68
+ gallery-horizontal-end SVG as a currentColor mask so it follows the native
69
+ nav hover/active colors without changing the shell's 16px icon rhythm. */
70
+ [data-dsh-coding-sidebar-settings-nav] > svg:first-child {
71
+ display: none;
72
+ }
73
+
74
+ [data-dsh-coding-sidebar-settings-nav]::before {
75
+ content: '';
76
+ flex: none;
77
+ width: 16px;
78
+ height: 16px;
79
+ background: currentColor;
80
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 7v10'/%3E%3Cpath d='M6 5v14'/%3E%3Crect width='12' height='18' x='10' y='3' rx='2'/%3E%3C/svg%3E") center / contain no-repeat;
81
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 7v10'/%3E%3Cpath d='M6 5v14'/%3E%3Crect width='12' height='18' x='10' y='3' rx='2'/%3E%3C/svg%3E") center / contain no-repeat;
82
+ }
83
+
84
+ @media (prefers-reduced-motion: reduce) {
85
+ #root,
86
+ #root [data-dsh-frame] > [data-pane="conversation"],
87
+ #root :has(> [data-slot="conversation"]) {
88
+ transition: none;
89
+ }
90
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Lazy chunk view wrapper: mounts a component that lives in a lazy chunk,
3
+ * showing a loading placeholder while the chunk script loads and an error +
4
+ * retry affordance on failure. Used by the built-in tab/viewer descriptors.
5
+ *
6
+ * Contract note: {@link lazyChunkComponent} returns a plain render-prop
7
+ * function — the descriptor contract is `component: (props) => ReactNode`,
8
+ * and the repo renders descriptors BOTH ways: Sidebar calls
9
+ * `descriptor.component(props)` directly, EditorHost renders it via
10
+ * `createElement`. The wrapper function body therefore contains no hooks;
11
+ * all state lives in the inner {@link LazyChunkView} component.
12
+ */
13
+ import { createElement, useEffect, useState, type ComponentType, type ReactNode } from 'react'
14
+ import { loadChunk, type ChunkExports, type ChunkName } from './chunk-loader.ts'
15
+ import { t } from './locales.ts'
16
+ import css from './sidebar.module.css'
17
+
18
+ interface LazyChunkViewProps<P> {
19
+ chunk: ChunkName
20
+ /** Module-level-stable selector (an inline lambda would re-trigger the effect). */
21
+ pick: (mod: ChunkExports) => ComponentType<P> | undefined
22
+ props: P
23
+ }
24
+
25
+ function LazyChunkView<P>({ chunk, pick, props }: LazyChunkViewProps<P>): ReactNode {
26
+ const [attempt, setAttempt] = useState(0)
27
+ const [state, setState] = useState<
28
+ | { status: 'loading' }
29
+ | { status: 'error'; message: string }
30
+ | { status: 'ready'; Comp: ComponentType<any> }
31
+ >({ status: 'loading' })
32
+
33
+ useEffect(() => {
34
+ let cancelled = false
35
+ setState({ status: 'loading' })
36
+ loadChunk(chunk).then((mod) => {
37
+ if (cancelled) return
38
+ const Comp = pick(mod)
39
+ if (Comp === undefined) {
40
+ setState({ status: 'error', message: `[dsh-coding-sidebar] chunk "${chunk}" is missing its component` })
41
+ return
42
+ }
43
+ setState({ status: 'ready', Comp })
44
+ }).catch((error: unknown) => {
45
+ if (cancelled) return
46
+ setState({ status: 'error', message: error instanceof Error ? error.message : String(error) })
47
+ })
48
+ return () => { cancelled = true }
49
+ }, [chunk, pick, attempt])
50
+
51
+ if (state.status === 'loading') {
52
+ return <div className={css.editorPlaceholder}>{t('loading')}</div>
53
+ }
54
+ if (state.status === 'error') {
55
+ return (
56
+ <div className={css.editorError}>
57
+ <span>{state.message}</span>
58
+ <button
59
+ type="button"
60
+ className={css.terminalRetry}
61
+ onClick={() => { setAttempt(current => current + 1) }}
62
+ >
63
+ {t('terminalRetry')}
64
+ </button>
65
+ </div>
66
+ )
67
+ }
68
+ return createElement(state.Comp, props)
69
+ }
70
+
71
+ /**
72
+ * Build a descriptor-compatible lazy wrapper for a chunk-resident component.
73
+ * The returned function is the descriptor `component` itself: it returns an
74
+ * element and never calls hooks, so both invocation styles (plain function
75
+ * call and createElement/JSX render) work. `pick` must be a module-level
76
+ * function (stable identity) — an inline lambda would re-trigger the load
77
+ * effect on every render.
78
+ * @param chunk - the chunk name (see chunk-loader.ts).
79
+ * @param pick - select the component from the chunk's exports.
80
+ */
81
+ export function lazyChunkComponent<P extends object>(
82
+ chunk: ChunkName,
83
+ pick: (mod: ChunkExports) => ComponentType<P> | undefined,
84
+ ): (props: P) => ReactNode {
85
+ return (props: P) => createElement(
86
+ LazyChunkView as ComponentType<LazyChunkViewProps<P>>,
87
+ { chunk, pick, props },
88
+ )
89
+ }
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Chat/GUI external-link interception: clicking an http(s) link that points
3
+ * OUTSIDE the GUI (chat messages, tool rows, prose mentions) opens the
4
+ * sidebar instead of a new browser tab. Gated by the caller through
5
+ * `takeoverEnabled(url)` — the `browserInterceptLinks` master, the URL's
6
+ * protocol flag (`browserInterceptHttp` / `browserInterceptHttps`) and the
7
+ * target tab's enable switch — and a Ctrl/Cmd/Shift/Alt-modified click
8
+ * always bypasses the takeover so the user can still force a real browser
9
+ * tab.
10
+ *
11
+ * Only the GUI's OWN document is watched — links inside the browser tab's
12
+ * sandboxed iframe live in another document and never bubble here (and
13
+ * their clicks must keep working inside the sidebar).
14
+ */
15
+
16
+ /** The pure decision: the URL to open in the sidebar, or null to let the
17
+ * click fall through. Extracted so the policy is unit-testable without a
18
+ * DOM. `anchorHref` must be the ABSOLUTE href (`<a>.href` already is).
19
+ * The protocol/same-origin policy lives HERE; the prefs gates (master +
20
+ * protocol flags + target enablement) live in the caller's
21
+ * `takeoverEnabled(url)` callback. */
22
+ export function shouldInterceptLink(anchorHref: string, selfOrigin: string): string | null {
23
+ let url: URL
24
+ try {
25
+ url = new URL(anchorHref)
26
+ } catch {
27
+ return null
28
+ }
29
+ if (url.protocol !== 'http:' && url.protocol !== 'https:') return null
30
+ // Same-origin links are GUI-internal navigation (settings pages, tool
31
+ // docs) — never routed into the sidebar.
32
+ try {
33
+ if (url.origin === new URL(selfOrigin).origin) return null
34
+ } catch {
35
+ // Unparsable selfOrigin (never in practice): intercept defensively.
36
+ }
37
+ return url.href
38
+ }
39
+
40
+ /** Whether a left-click may be taken over (unmodified left click only). */
41
+ export function isPlainLeftClick(event: { button: number; metaKey: boolean; ctrlKey: boolean; shiftKey: boolean; altKey: boolean }): boolean {
42
+ return event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey
43
+ }
44
+
45
+ /**
46
+ * Register the document-level click capture that funnels external links
47
+ * into the sidebar. Returns the disposer (HMR-safe).
48
+ */
49
+ export function registerLinkInterception(opts: {
50
+ /** Whether the takeover may happen for THIS url (the caller's prefs
51
+ * gates: master switch, protocol flag, target enablement). */
52
+ takeoverEnabled: (url: URL) => boolean
53
+ /** Open the sidebar tab at `url` (the caller resolves the target type). */
54
+ openInSidebar: (url: string) => void
55
+ /** The GUI's own origin (window.location.origin at registration). */
56
+ selfOrigin: string
57
+ }): () => void {
58
+ const onClick = (event: MouseEvent): void => {
59
+ if (!isPlainLeftClick(event)) return
60
+ if (event.defaultPrevented) return
61
+ const target = event.target
62
+ if (target === null || typeof (target as Element).closest !== 'function') return
63
+ const anchor = (target as Element).closest('a[href]') as HTMLAnchorElement | null
64
+ if (anchor === null) return
65
+ const url = shouldInterceptLink(anchor.href, opts.selfOrigin)
66
+ if (url === null) return
67
+ if (!opts.takeoverEnabled(new URL(url))) return
68
+ event.preventDefault()
69
+ opts.openInSidebar(url)
70
+ }
71
+ document.addEventListener('click', onClick, true)
72
+ return () => { document.removeEventListener('click', onClick, true) }
73
+ }