@wonderwhy-er/desktop-commander 0.2.37 → 0.2.39

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 (383) hide show
  1. package/README.md +290 -100
  2. package/dist/command-manager.js +6 -3
  3. package/dist/config-field-definitions.d.ts +41 -0
  4. package/dist/config-field-definitions.js +37 -0
  5. package/dist/config-manager.d.ts +2 -0
  6. package/dist/config-manager.js +22 -2
  7. package/dist/handlers/filesystem-handlers.d.ts +5 -0
  8. package/dist/handlers/filesystem-handlers.js +19 -12
  9. package/dist/remote-device/desktop-commander-integration.js +1 -1
  10. package/dist/remote-device/remote-channel.js +1 -1
  11. package/dist/search-manager.js +31 -38
  12. package/dist/server.js +11 -4
  13. package/dist/terminal-manager.js +4 -2
  14. package/dist/tools/config.d.ts +71 -0
  15. package/dist/tools/config.js +117 -2
  16. package/dist/tools/edit.js +34 -1
  17. package/dist/tools/filesystem.js +91 -3
  18. package/dist/tools/improved-process-tools.js +2 -1
  19. package/dist/tools/schemas.d.ts +3 -0
  20. package/dist/tools/schemas.js +1 -0
  21. package/dist/types.d.ts +0 -1
  22. package/dist/ui/config-editor/app.d.ts +43 -0
  23. package/dist/ui/config-editor/app.js +840 -0
  24. package/dist/ui/config-editor/array-modal.d.ts +19 -0
  25. package/dist/ui/config-editor/array-modal.js +185 -0
  26. package/dist/ui/config-editor/config-editor-runtime.js +150 -0
  27. package/dist/ui/config-editor/index.html +13 -0
  28. package/dist/ui/config-editor/main.js +2 -0
  29. package/dist/ui/config-editor/src/App.d.ts +43 -0
  30. package/dist/ui/config-editor/src/App.js +840 -0
  31. package/dist/ui/config-editor/src/array-modal.d.ts +19 -0
  32. package/dist/ui/config-editor/src/array-modal.js +185 -0
  33. package/dist/ui/config-editor/src/components/layout.d.ts +4 -0
  34. package/dist/ui/config-editor/src/components/layout.js +83 -0
  35. package/dist/ui/config-editor/src/components/toolbar.d.ts +1 -0
  36. package/dist/ui/config-editor/src/components/toolbar.js +21 -0
  37. package/dist/ui/config-editor/src/config-values.d.ts +6 -0
  38. package/dist/ui/config-editor/src/config-values.js +61 -0
  39. package/dist/ui/config-editor/src/contracts.d.ts +14 -0
  40. package/dist/ui/config-editor/src/contracts.js +3 -0
  41. package/dist/ui/config-editor/src/directory-browser.d.ts +6 -0
  42. package/dist/ui/config-editor/src/directory-browser.js +71 -0
  43. package/dist/ui/config-editor/src/layout.d.ts +5 -0
  44. package/dist/ui/config-editor/src/layout.js +90 -0
  45. package/dist/ui/config-editor/src/main.js +2 -0
  46. package/dist/ui/config-editor/src/parsing.d.ts +5 -0
  47. package/dist/ui/config-editor/src/parsing.js +50 -0
  48. package/dist/ui/config-editor/src/toolbar.d.ts +1 -0
  49. package/dist/ui/config-editor/src/toolbar.js +18 -0
  50. package/dist/ui/config-editor/src/types.d.ts +17 -0
  51. package/dist/ui/config-editor/src/types.js +3 -0
  52. package/dist/ui/config-editor/src/utils/config-values.d.ts +9 -0
  53. package/dist/ui/config-editor/src/utils/config-values.js +61 -0
  54. package/dist/ui/config-editor/src/utils/directory-browser.d.ts +31 -0
  55. package/dist/ui/config-editor/src/utils/directory-browser.js +201 -0
  56. package/dist/ui/config-editor/src/utils/parsing.d.ts +8 -0
  57. package/dist/ui/config-editor/src/utils/parsing.js +50 -0
  58. package/dist/ui/config-editor/styles.css +587 -0
  59. package/dist/ui/file-preview/app.d.ts +8 -0
  60. package/dist/ui/file-preview/app.js +2020 -0
  61. package/dist/ui/file-preview/components/code-viewer.d.ts +6 -0
  62. package/dist/ui/file-preview/components/code-viewer.js +73 -0
  63. package/dist/ui/file-preview/components/highlighting.d.ts +2 -0
  64. package/dist/ui/file-preview/components/highlighting.js +54 -0
  65. package/dist/ui/file-preview/components/html-renderer.d.ts +5 -0
  66. package/dist/ui/file-preview/components/html-renderer.js +47 -0
  67. package/dist/ui/file-preview/components/markdown-renderer.d.ts +1 -0
  68. package/dist/ui/file-preview/components/markdown-renderer.js +67 -0
  69. package/dist/ui/file-preview/components/toolbar.d.ts +6 -0
  70. package/dist/ui/file-preview/components/toolbar.js +75 -0
  71. package/dist/ui/file-preview/image-preview.d.ts +3 -0
  72. package/dist/ui/file-preview/image-preview.js +21 -0
  73. package/dist/ui/file-preview/main.js +5 -0
  74. package/dist/ui/file-preview/markdown/editor.d.ts +36 -0
  75. package/dist/ui/file-preview/markdown/editor.js +643 -0
  76. package/dist/ui/file-preview/markdown/linking.d.ts +9 -0
  77. package/dist/ui/file-preview/markdown/linking.js +210 -0
  78. package/dist/ui/file-preview/markdown/outline.d.ts +7 -0
  79. package/dist/ui/file-preview/markdown/outline.js +40 -0
  80. package/dist/ui/file-preview/markdown/preview.d.ts +8 -0
  81. package/dist/ui/file-preview/markdown/preview.js +33 -0
  82. package/dist/ui/file-preview/markdown/slugify.d.ts +3 -0
  83. package/dist/ui/file-preview/markdown/slugify.js +31 -0
  84. package/dist/ui/file-preview/markdown/toc.d.ts +11 -0
  85. package/dist/ui/file-preview/markdown/toc.js +75 -0
  86. package/dist/ui/file-preview/markdown/utils.d.ts +1 -0
  87. package/dist/ui/file-preview/markdown/utils.js +15 -0
  88. package/dist/ui/file-preview/markdown/workspace-controller.d.ts +25 -0
  89. package/dist/ui/file-preview/markdown/workspace-controller.js +40 -0
  90. package/dist/ui/file-preview/preview-runtime.js +399 -13969
  91. package/dist/ui/file-preview/shared/preview-file-types.d.ts +1 -1
  92. package/dist/ui/file-preview/shared/preview-file-types.js +3 -1
  93. package/dist/ui/file-preview/src/App.d.ts +4 -0
  94. package/dist/ui/file-preview/src/App.js +564 -0
  95. package/dist/ui/file-preview/src/components/CodeViewer.d.ts +6 -0
  96. package/dist/ui/file-preview/src/components/CodeViewer.js +60 -0
  97. package/dist/ui/file-preview/src/components/HtmlRenderer.d.ts +8 -0
  98. package/dist/ui/file-preview/src/components/HtmlRenderer.js +45 -0
  99. package/dist/ui/file-preview/src/components/MarkdownRenderer.d.ts +1 -0
  100. package/dist/ui/file-preview/src/components/MarkdownRenderer.js +15 -0
  101. package/dist/ui/file-preview/src/components/editor-toolbar.d.ts +15 -0
  102. package/dist/ui/file-preview/src/components/editor-toolbar.js +384 -0
  103. package/dist/ui/file-preview/src/components/html-renderer.d.ts +1 -5
  104. package/dist/ui/file-preview/src/components/html-renderer.js +11 -27
  105. package/dist/ui/file-preview/src/components/markdown-editor.d.ts +29 -0
  106. package/dist/ui/file-preview/src/components/markdown-editor.js +535 -0
  107. package/dist/ui/file-preview/src/components/markdown-renderer.js +47 -9
  108. package/dist/ui/file-preview/src/directory-controller.d.ts +8 -0
  109. package/dist/ui/file-preview/src/directory-controller.js +233 -0
  110. package/dist/ui/file-preview/src/document-layout.d.ts +20 -0
  111. package/dist/ui/file-preview/src/document-layout.js +109 -0
  112. package/dist/ui/file-preview/src/document-outline.d.ts +17 -0
  113. package/dist/ui/file-preview/src/document-outline.js +97 -0
  114. package/dist/ui/file-preview/src/document-workspace.d.ts +19 -0
  115. package/dist/ui/file-preview/src/document-workspace.js +33 -0
  116. package/dist/ui/file-preview/src/file-type-handlers.d.ts +10 -0
  117. package/dist/ui/file-preview/src/file-type-handlers.js +98 -0
  118. package/dist/ui/file-preview/src/host/external-actions.d.ts +19 -0
  119. package/dist/ui/file-preview/src/host/external-actions.js +94 -0
  120. package/dist/ui/file-preview/src/host/selection-context.d.ts +9 -0
  121. package/dist/ui/file-preview/src/host/selection-context.js +106 -0
  122. package/dist/ui/file-preview/src/markdown/block-merge.d.ts +25 -0
  123. package/dist/ui/file-preview/src/markdown/block-merge.js +86 -0
  124. package/dist/ui/file-preview/src/markdown/conflict-dialog.d.ts +40 -0
  125. package/dist/ui/file-preview/src/markdown/conflict-dialog.js +163 -0
  126. package/dist/ui/file-preview/src/markdown/controller.d.ts +38 -0
  127. package/dist/ui/file-preview/src/markdown/controller.js +921 -0
  128. package/dist/ui/file-preview/src/markdown/editor.d.ts +35 -0
  129. package/dist/ui/file-preview/src/markdown/editor.js +691 -0
  130. package/dist/ui/file-preview/src/markdown/link-modal.d.ts +13 -0
  131. package/dist/ui/file-preview/src/markdown/link-modal.js +213 -0
  132. package/dist/ui/file-preview/src/markdown/linking.d.ts +16 -0
  133. package/dist/ui/file-preview/src/markdown/linking.js +228 -0
  134. package/dist/ui/file-preview/src/markdown/outline.d.ts +2 -0
  135. package/dist/ui/file-preview/src/markdown/outline.js +16 -0
  136. package/dist/ui/file-preview/src/markdown/parser.d.ts +30 -0
  137. package/dist/ui/file-preview/src/markdown/parser.js +38 -0
  138. package/dist/ui/file-preview/src/markdown/preview.d.ts +1 -0
  139. package/dist/ui/file-preview/src/markdown/preview.js +20 -0
  140. package/dist/ui/file-preview/src/markdown/raw-editor.d.ts +8 -0
  141. package/dist/ui/file-preview/src/markdown/raw-editor.js +61 -0
  142. package/dist/ui/file-preview/src/markdown/selection-toolbar.d.ts +14 -0
  143. package/dist/ui/file-preview/src/markdown/selection-toolbar.js +128 -0
  144. package/dist/ui/file-preview/src/markdown/slugify.d.ts +3 -0
  145. package/dist/ui/file-preview/src/markdown/slugify.js +31 -0
  146. package/dist/ui/file-preview/src/markdown/toc.d.ts +11 -0
  147. package/dist/ui/file-preview/src/markdown/toc.js +75 -0
  148. package/dist/ui/file-preview/src/markdown/utils.d.ts +1 -0
  149. package/dist/ui/file-preview/src/markdown/utils.js +15 -0
  150. package/dist/ui/file-preview/src/markdown-workspace/editor.d.ts +36 -0
  151. package/dist/ui/file-preview/src/markdown-workspace/editor.js +643 -0
  152. package/dist/ui/file-preview/src/markdown-workspace/linking.d.ts +9 -0
  153. package/dist/ui/file-preview/src/markdown-workspace/linking.js +210 -0
  154. package/dist/ui/file-preview/src/markdown-workspace/outline.d.ts +7 -0
  155. package/dist/ui/file-preview/src/markdown-workspace/outline.js +40 -0
  156. package/dist/ui/file-preview/src/markdown-workspace/preview.d.ts +8 -0
  157. package/dist/ui/file-preview/src/markdown-workspace/preview.js +33 -0
  158. package/dist/ui/file-preview/src/markdown-workspace/slugify.d.ts +3 -0
  159. package/dist/ui/file-preview/src/markdown-workspace/slugify.js +31 -0
  160. package/dist/ui/file-preview/src/markdown-workspace/toc.d.ts +11 -0
  161. package/dist/ui/file-preview/src/markdown-workspace/toc.js +75 -0
  162. package/dist/ui/file-preview/src/markdown-workspace/utils.d.ts +1 -0
  163. package/dist/ui/file-preview/src/markdown-workspace/utils.js +15 -0
  164. package/dist/ui/file-preview/src/markdown-workspace/workspace-controller.d.ts +25 -0
  165. package/dist/ui/file-preview/src/markdown-workspace/workspace-controller.js +40 -0
  166. package/dist/ui/file-preview/src/model.d.ts +34 -0
  167. package/dist/ui/file-preview/src/panel-actions.d.ts +17 -0
  168. package/dist/ui/file-preview/src/panel-actions.js +182 -0
  169. package/dist/ui/file-preview/src/path-utils.d.ts +6 -0
  170. package/dist/ui/file-preview/src/path-utils.js +64 -0
  171. package/dist/ui/file-preview/src/payload-utils.d.ts +11 -0
  172. package/dist/ui/file-preview/src/payload-utils.js +94 -0
  173. package/dist/ui/file-preview/styles.css +1144 -277
  174. package/dist/ui/file-preview/types.d.ts +1 -0
  175. package/dist/ui/file-preview/types.js +1 -0
  176. package/dist/ui/resources.d.ts +7 -0
  177. package/dist/ui/resources.js +16 -2
  178. package/dist/ui/server-integration.d.ts +13 -0
  179. package/dist/ui/server-integration.js +31 -0
  180. package/dist/ui/shared/ToolHeader.d.ts +9 -0
  181. package/dist/ui/shared/ToolHeader.js +29 -0
  182. package/dist/ui/shared/app-bootstrap.d.ts +9 -0
  183. package/dist/ui/shared/app-bootstrap.js +15 -0
  184. package/dist/ui/shared/compact-row.d.ts +11 -0
  185. package/dist/ui/shared/compact-row.js +18 -0
  186. package/dist/ui/shared/guards.d.ts +1 -0
  187. package/dist/ui/shared/guards.js +3 -0
  188. package/dist/ui/shared/host-context.d.ts +15 -0
  189. package/dist/ui/shared/host-context.js +51 -0
  190. package/dist/ui/shared/host-lifecycle.d.ts +1 -0
  191. package/dist/ui/shared/host-lifecycle.js +8 -2
  192. package/dist/ui/shared/tool-bridge.d.ts +30 -0
  193. package/dist/ui/shared/tool-bridge.js +137 -0
  194. package/dist/ui/shared/tool-shell.d.ts +9 -0
  195. package/dist/ui/shared/tool-shell.js +46 -4
  196. package/dist/ui/shared/ui-event-tracker.d.ts +9 -0
  197. package/dist/ui/shared/ui-event-tracker.js +27 -0
  198. package/dist/ui/shared/widget-state.d.ts +6 -1
  199. package/dist/ui/shared/widget-state.js +102 -4
  200. package/dist/utils/capture.js +3 -3
  201. package/dist/utils/files/base.d.ts +2 -0
  202. package/dist/utils/open-browser.js +1 -1
  203. package/dist/utils/ui-call-context.d.ts +8 -0
  204. package/dist/utils/ui-call-context.js +72 -0
  205. package/dist/version.d.ts +1 -1
  206. package/dist/version.js +1 -1
  207. package/package.json +13 -4
  208. package/dist/data/spec-kit-prompts.json +0 -123
  209. package/dist/handlers/node-handlers.d.ts +0 -6
  210. package/dist/handlers/node-handlers.js +0 -73
  211. package/dist/handlers/test-crash-handler.d.ts +0 -11
  212. package/dist/handlers/test-crash-handler.js +0 -26
  213. package/dist/http-index.d.ts +0 -45
  214. package/dist/http-index.js +0 -51
  215. package/dist/http-server-auto-tunnel.js +0 -667
  216. package/dist/http-server-named-tunnel.d.ts +0 -2
  217. package/dist/http-server-named-tunnel.js +0 -167
  218. package/dist/http-server-tunnel.d.ts +0 -2
  219. package/dist/http-server-tunnel.js +0 -111
  220. package/dist/http-server.d.ts +0 -2
  221. package/dist/http-server.js +0 -270
  222. package/dist/index-oauth.d.ts +0 -2
  223. package/dist/index-oauth.js +0 -201
  224. package/dist/oauth/auth-middleware.d.ts +0 -20
  225. package/dist/oauth/auth-middleware.js +0 -62
  226. package/dist/oauth/index.d.ts +0 -3
  227. package/dist/oauth/index.js +0 -3
  228. package/dist/oauth/oauth-manager.d.ts +0 -80
  229. package/dist/oauth/oauth-manager.js +0 -179
  230. package/dist/oauth/oauth-routes.d.ts +0 -3
  231. package/dist/oauth/oauth-routes.js +0 -377
  232. package/dist/oauth/provider.d.ts +0 -22
  233. package/dist/oauth/provider.js +0 -124
  234. package/dist/oauth/server.d.ts +0 -18
  235. package/dist/oauth/server.js +0 -160
  236. package/dist/oauth/types.d.ts +0 -54
  237. package/dist/oauth/types.js +0 -2
  238. package/dist/remote-device/templates/auth-success.d.ts +0 -1
  239. package/dist/remote-device/templates/auth-success.js +0 -30
  240. package/dist/setup.log +0 -275
  241. package/dist/test-setup.js +0 -14
  242. package/dist/tools/docx/builders/html-builder.d.ts +0 -17
  243. package/dist/tools/docx/builders/html-builder.js +0 -92
  244. package/dist/tools/docx/builders/image.d.ts +0 -14
  245. package/dist/tools/docx/builders/image.js +0 -84
  246. package/dist/tools/docx/builders/index.d.ts +0 -11
  247. package/dist/tools/docx/builders/index.js +0 -11
  248. package/dist/tools/docx/builders/markdown-builder.d.ts +0 -2
  249. package/dist/tools/docx/builders/markdown-builder.js +0 -260
  250. package/dist/tools/docx/builders/paragraph.d.ts +0 -12
  251. package/dist/tools/docx/builders/paragraph.js +0 -29
  252. package/dist/tools/docx/builders/table.d.ts +0 -10
  253. package/dist/tools/docx/builders/table.js +0 -138
  254. package/dist/tools/docx/builders/utils.d.ts +0 -5
  255. package/dist/tools/docx/builders/utils.js +0 -18
  256. package/dist/tools/docx/constants.d.ts +0 -32
  257. package/dist/tools/docx/constants.js +0 -61
  258. package/dist/tools/docx/converters/markdown-to-html.d.ts +0 -17
  259. package/dist/tools/docx/converters/markdown-to-html.js +0 -111
  260. package/dist/tools/docx/create.d.ts +0 -21
  261. package/dist/tools/docx/create.js +0 -386
  262. package/dist/tools/docx/dom.d.ts +0 -139
  263. package/dist/tools/docx/dom.js +0 -448
  264. package/dist/tools/docx/errors.d.ts +0 -28
  265. package/dist/tools/docx/errors.js +0 -48
  266. package/dist/tools/docx/extractors/images.d.ts +0 -14
  267. package/dist/tools/docx/extractors/images.js +0 -40
  268. package/dist/tools/docx/extractors/metadata.d.ts +0 -14
  269. package/dist/tools/docx/extractors/metadata.js +0 -64
  270. package/dist/tools/docx/extractors/sections.d.ts +0 -14
  271. package/dist/tools/docx/extractors/sections.js +0 -61
  272. package/dist/tools/docx/html.d.ts +0 -17
  273. package/dist/tools/docx/html.js +0 -111
  274. package/dist/tools/docx/index.d.ts +0 -10
  275. package/dist/tools/docx/index.js +0 -10
  276. package/dist/tools/docx/markdown.d.ts +0 -84
  277. package/dist/tools/docx/markdown.js +0 -507
  278. package/dist/tools/docx/modify.d.ts +0 -28
  279. package/dist/tools/docx/modify.js +0 -271
  280. package/dist/tools/docx/operations/handlers/index.d.ts +0 -39
  281. package/dist/tools/docx/operations/handlers/index.js +0 -152
  282. package/dist/tools/docx/operations/html-manipulator.d.ts +0 -24
  283. package/dist/tools/docx/operations/html-manipulator.js +0 -352
  284. package/dist/tools/docx/operations/index.d.ts +0 -14
  285. package/dist/tools/docx/operations/index.js +0 -61
  286. package/dist/tools/docx/operations/operation-handlers.d.ts +0 -3
  287. package/dist/tools/docx/operations/operation-handlers.js +0 -67
  288. package/dist/tools/docx/operations/preprocessor.d.ts +0 -14
  289. package/dist/tools/docx/operations/preprocessor.js +0 -44
  290. package/dist/tools/docx/operations/xml-replacer.d.ts +0 -9
  291. package/dist/tools/docx/operations/xml-replacer.js +0 -35
  292. package/dist/tools/docx/operations.d.ts +0 -13
  293. package/dist/tools/docx/operations.js +0 -13
  294. package/dist/tools/docx/ops/delete-paragraph-at-body-index.d.ts +0 -11
  295. package/dist/tools/docx/ops/delete-paragraph-at-body-index.js +0 -23
  296. package/dist/tools/docx/ops/header-replace-text-exact.d.ts +0 -13
  297. package/dist/tools/docx/ops/header-replace-text-exact.js +0 -55
  298. package/dist/tools/docx/ops/index.d.ts +0 -17
  299. package/dist/tools/docx/ops/index.js +0 -70
  300. package/dist/tools/docx/ops/insert-image-after-text.d.ts +0 -24
  301. package/dist/tools/docx/ops/insert-image-after-text.js +0 -128
  302. package/dist/tools/docx/ops/insert-paragraph-after-text.d.ts +0 -12
  303. package/dist/tools/docx/ops/insert-paragraph-after-text.js +0 -74
  304. package/dist/tools/docx/ops/insert-table-after-text.d.ts +0 -19
  305. package/dist/tools/docx/ops/insert-table-after-text.js +0 -57
  306. package/dist/tools/docx/ops/replace-hyperlink-url.d.ts +0 -12
  307. package/dist/tools/docx/ops/replace-hyperlink-url.js +0 -37
  308. package/dist/tools/docx/ops/replace-paragraph-at-body-index.d.ts +0 -9
  309. package/dist/tools/docx/ops/replace-paragraph-at-body-index.js +0 -25
  310. package/dist/tools/docx/ops/replace-paragraph-text-exact.d.ts +0 -21
  311. package/dist/tools/docx/ops/replace-paragraph-text-exact.js +0 -36
  312. package/dist/tools/docx/ops/replace-table-cell-text.d.ts +0 -25
  313. package/dist/tools/docx/ops/replace-table-cell-text.js +0 -85
  314. package/dist/tools/docx/ops/set-color-for-paragraph-exact.d.ts +0 -9
  315. package/dist/tools/docx/ops/set-color-for-paragraph-exact.js +0 -24
  316. package/dist/tools/docx/ops/set-color-for-style.d.ts +0 -13
  317. package/dist/tools/docx/ops/set-color-for-style.js +0 -31
  318. package/dist/tools/docx/ops/set-paragraph-style-at-body-index.d.ts +0 -8
  319. package/dist/tools/docx/ops/set-paragraph-style-at-body-index.js +0 -57
  320. package/dist/tools/docx/ops/table-set-cell-text.d.ts +0 -9
  321. package/dist/tools/docx/ops/table-set-cell-text.js +0 -40
  322. package/dist/tools/docx/parsers/image-extractor.d.ts +0 -18
  323. package/dist/tools/docx/parsers/image-extractor.js +0 -61
  324. package/dist/tools/docx/parsers/index.d.ts +0 -9
  325. package/dist/tools/docx/parsers/index.js +0 -9
  326. package/dist/tools/docx/parsers/paragraph-parser.d.ts +0 -2
  327. package/dist/tools/docx/parsers/paragraph-parser.js +0 -88
  328. package/dist/tools/docx/parsers/table-parser.d.ts +0 -9
  329. package/dist/tools/docx/parsers/table-parser.js +0 -72
  330. package/dist/tools/docx/parsers/xml-parser.d.ts +0 -25
  331. package/dist/tools/docx/parsers/xml-parser.js +0 -71
  332. package/dist/tools/docx/parsers/zip-reader.d.ts +0 -23
  333. package/dist/tools/docx/parsers/zip-reader.js +0 -52
  334. package/dist/tools/docx/read.d.ts +0 -27
  335. package/dist/tools/docx/read.js +0 -308
  336. package/dist/tools/docx/relationships.d.ts +0 -22
  337. package/dist/tools/docx/relationships.js +0 -76
  338. package/dist/tools/docx/structure.d.ts +0 -25
  339. package/dist/tools/docx/structure.js +0 -102
  340. package/dist/tools/docx/styled-html-parser.d.ts +0 -23
  341. package/dist/tools/docx/styled-html-parser.js +0 -1262
  342. package/dist/tools/docx/types.d.ts +0 -213
  343. package/dist/tools/docx/types.js +0 -5
  344. package/dist/tools/docx/utils/escaping.d.ts +0 -13
  345. package/dist/tools/docx/utils/escaping.js +0 -26
  346. package/dist/tools/docx/utils/images.d.ts +0 -9
  347. package/dist/tools/docx/utils/images.js +0 -26
  348. package/dist/tools/docx/utils/index.d.ts +0 -12
  349. package/dist/tools/docx/utils/index.js +0 -17
  350. package/dist/tools/docx/utils/markdown.d.ts +0 -13
  351. package/dist/tools/docx/utils/markdown.js +0 -32
  352. package/dist/tools/docx/utils/paths.d.ts +0 -15
  353. package/dist/tools/docx/utils/paths.js +0 -27
  354. package/dist/tools/docx/utils/versioning.d.ts +0 -25
  355. package/dist/tools/docx/utils/versioning.js +0 -55
  356. package/dist/tools/docx/utils.d.ts +0 -101
  357. package/dist/tools/docx/utils.js +0 -299
  358. package/dist/tools/docx/validate.d.ts +0 -33
  359. package/dist/tools/docx/validate.js +0 -49
  360. package/dist/tools/docx/validators.d.ts +0 -13
  361. package/dist/tools/docx/validators.js +0 -40
  362. package/dist/tools/docx/write.d.ts +0 -17
  363. package/dist/tools/docx/write.js +0 -88
  364. package/dist/tools/docx/xml-view-test.js +0 -63
  365. package/dist/tools/docx/xml-view.d.ts +0 -56
  366. package/dist/tools/docx/xml-view.js +0 -169
  367. package/dist/tools/docx/zip.d.ts +0 -21
  368. package/dist/tools/docx/zip.js +0 -35
  369. package/dist/tools/pdf-processor.js +0 -3
  370. package/dist/tools/search.d.ts +0 -32
  371. package/dist/tools/search.js +0 -202
  372. package/dist/ui/file-preview/src/app.d.ts +0 -4
  373. package/dist/ui/file-preview/src/app.js +0 -800
  374. package/dist/utils/crash-logger.d.ts +0 -18
  375. package/dist/utils/crash-logger.js +0 -44
  376. package/dist/utils/dedent.d.ts +0 -8
  377. package/dist/utils/dedent.js +0 -38
  378. /package/dist/{http-server-auto-tunnel.d.ts → ui/config-editor/main.d.ts} +0 -0
  379. /package/dist/{test-docx.d.ts → ui/config-editor/src/main.d.ts} +0 -0
  380. /package/dist/{tools/docx/xml-view-test.d.ts → ui/file-preview/main.d.ts} +0 -0
  381. /package/dist/ui/file-preview/src/components/{toolbar.d.ts → Toolbar.d.ts} +0 -0
  382. /package/dist/ui/file-preview/src/components/{toolbar.js → Toolbar.js} +0 -0
  383. /package/dist/{tools/pdf-processor.d.ts → ui/file-preview/src/model.js} +0 -0
@@ -1,800 +0,0 @@
1
- /**
2
- * Top-level controller for the File Preview app. It routes structured content into the appropriate renderer, handles host events, and coordinates user-facing state changes.
3
- */
4
- import { formatJsonIfPossible, inferLanguageFromPath, renderCodeViewer } from './components/code-viewer.js';
5
- import { renderHtmlPreview } from './components/html-renderer.js';
6
- import { renderMarkdown } from './components/markdown-renderer.js';
7
- import { escapeHtml } from './components/highlighting.js';
8
- import { isAllowedImageMimeType, normalizeImageMimeType } from './image-preview.js';
9
- import { createWindowRpcClient, isTrustedParentMessageSource } from '../../shared/rpc-client.js';
10
- import { createToolShellController } from '../../shared/tool-shell.js';
11
- import { createUiHostLifecycle } from '../../shared/host-lifecycle.js';
12
- import { createUiThemeAdapter } from '../../shared/theme-adaptation.js';
13
- import { createWidgetStateStorage } from '../../shared/widget-state.js';
14
- let isExpanded = false;
15
- let previewShownFired = false;
16
- let onRender;
17
- let trackUiEvent;
18
- let rpcCallTool;
19
- let rpcUpdateContext;
20
- let shellController;
21
- function getFileExtensionForAnalytics(filePath) {
22
- const normalizedPath = filePath.trim().replace(/\\/g, '/');
23
- const fileName = normalizedPath.split('/').pop() ?? normalizedPath;
24
- const dotIndex = fileName.lastIndexOf('.');
25
- if (dotIndex <= 0 || dotIndex === fileName.length - 1) {
26
- return 'none';
27
- }
28
- return fileName.slice(dotIndex + 1).toLowerCase();
29
- }
30
- function isObject(value) {
31
- return typeof value === 'object' && value !== null;
32
- }
33
- function isPreviewStructuredContent(value) {
34
- if (!isObject(value)) {
35
- return false;
36
- }
37
- return (typeof value.fileName === 'string' &&
38
- typeof value.filePath === 'string' &&
39
- typeof value.fileType === 'string' &&
40
- typeof value.content === 'string');
41
- }
42
- function readStructuredContentFromWindow() {
43
- const candidates = [
44
- window.__DC_FILE_PREVIEW__,
45
- window.__MCP_TOOL_RESULT__,
46
- window.toolResult,
47
- window.structuredContent
48
- ];
49
- for (const candidate of candidates) {
50
- if (!isObject(candidate)) {
51
- continue;
52
- }
53
- if (isPreviewStructuredContent(candidate.structuredContent)) {
54
- return candidate.structuredContent;
55
- }
56
- if (isPreviewStructuredContent(candidate)) {
57
- return candidate;
58
- }
59
- }
60
- return undefined;
61
- }
62
- function extractStructuredContent(value) {
63
- if (!isObject(value)) {
64
- return undefined;
65
- }
66
- if (isPreviewStructuredContent(value.structuredContent)) {
67
- return value.structuredContent;
68
- }
69
- if (isPreviewStructuredContent(value)) {
70
- return value;
71
- }
72
- return undefined;
73
- }
74
- function extractToolText(value) {
75
- if (!isObject(value)) {
76
- return undefined;
77
- }
78
- const content = value.content;
79
- if (!Array.isArray(content)) {
80
- return undefined;
81
- }
82
- for (const item of content) {
83
- if (!isObject(item)) {
84
- continue;
85
- }
86
- if (item.type === 'text' && typeof item.text === 'string' && item.text.trim().length > 0) {
87
- return item.text;
88
- }
89
- }
90
- return undefined;
91
- }
92
- function extractToolTextFromEvent(value) {
93
- if (!isObject(value)) {
94
- return undefined;
95
- }
96
- const direct = extractToolText(value);
97
- if (direct) {
98
- return direct;
99
- }
100
- if (isObject(value.result)) {
101
- const nested = extractToolText(value.result);
102
- if (nested) {
103
- return nested;
104
- }
105
- }
106
- if (isObject(value.params)) {
107
- const paramsText = extractToolText(value.params);
108
- if (paramsText) {
109
- return paramsText;
110
- }
111
- if (isObject(value.params.result)) {
112
- return extractToolText(value.params.result);
113
- }
114
- }
115
- return undefined;
116
- }
117
- function isLikelyUrl(filePath) {
118
- return /^https?:\/\//i.test(filePath);
119
- }
120
- function buildBreadcrumb(filePath) {
121
- const normalized = filePath.replace(/\\/g, '/');
122
- const parts = normalized.split('/').filter(Boolean);
123
- // Show last 3-4 meaningful segments as breadcrumb
124
- const tail = parts.slice(-4);
125
- return tail.map(p => escapeHtml(p)).join(' <span class="breadcrumb-sep">›</span> ');
126
- }
127
- function getParentDirectory(filePath) {
128
- const normalized = filePath.replace(/\\/g, '/');
129
- const lastSlash = normalized.lastIndexOf('/');
130
- if (lastSlash <= 0) {
131
- return filePath;
132
- }
133
- return normalized.slice(0, lastSlash);
134
- }
135
- function shellQuote(value) {
136
- return `'${value.replace(/'/g, `'\\''`)}'`;
137
- }
138
- function encodePowerShellCommand(script) {
139
- // PowerShell -EncodedCommand expects UTF-16LE bytes.
140
- const utf16leBytes = [];
141
- for (let index = 0; index < script.length; index += 1) {
142
- const codeUnit = script.charCodeAt(index);
143
- utf16leBytes.push(codeUnit & 0xff, codeUnit >> 8);
144
- }
145
- let binary = '';
146
- for (const byte of utf16leBytes) {
147
- binary += String.fromCharCode(byte);
148
- }
149
- return btoa(binary);
150
- }
151
- function buildOpenInFolderCommand(filePath) {
152
- const trimmedPath = filePath.trim();
153
- if (!trimmedPath || isLikelyUrl(trimmedPath)) {
154
- return undefined;
155
- }
156
- const userAgent = navigator.userAgent.toLowerCase();
157
- if (userAgent.includes('win')) {
158
- const escapedForPowerShell = trimmedPath.replace(/'/g, "''");
159
- const script = `Start-Process -FilePath explorer.exe -ArgumentList @('/select,','${escapedForPowerShell}')`;
160
- return `powershell.exe -NoProfile -NonInteractive -EncodedCommand ${encodePowerShellCommand(script)}`;
161
- }
162
- if (userAgent.includes('mac')) {
163
- return `open -R ${shellQuote(trimmedPath)}`;
164
- }
165
- return `xdg-open ${shellQuote(getParentDirectory(trimmedPath))}`;
166
- }
167
- function renderRawFallback(source) {
168
- return `<pre class="code-viewer"><code class="hljs language-text">${escapeHtml(source)}</code></pre>`;
169
- }
170
- function stripReadStatusLine(content) {
171
- // Remove the synthetic read status header shown by read_file pagination.
172
- return content.replace(/^\[Reading [^\]]+\]\r?\n?/, '');
173
- }
174
- function renderImageBody(payload) {
175
- const mimeType = normalizeImageMimeType(payload.mimeType);
176
- if (!isAllowedImageMimeType(mimeType)) {
177
- return {
178
- notice: 'Preview is unavailable for this image format.',
179
- html: '<div class="panel-content source-content"></div>'
180
- };
181
- }
182
- if (!payload.imageData || payload.imageData.trim().length === 0) {
183
- return {
184
- notice: 'Preview is unavailable because image data is missing.',
185
- html: '<div class="panel-content source-content"></div>'
186
- };
187
- }
188
- const src = `data:${mimeType};base64,${payload.imageData}`;
189
- return {
190
- html: `<div class="panel-content image-content"><div class="image-preview"><img src="${escapeHtml(src)}" alt="${escapeHtml(payload.fileName)}" loading="eager" decoding="async"></div></div>`
191
- };
192
- }
193
- function countContentLines(content) {
194
- const cleaned = stripReadStatusLine(content);
195
- if (cleaned === '')
196
- return 0;
197
- const lines = cleaned.split('\n');
198
- return lines[lines.length - 1] === '' ? lines.length - 1 : lines.length;
199
- }
200
- function parseReadRange(content) {
201
- // Parse "[Reading N lines from line M (total: T lines, R remaining)]"
202
- // or "[Reading N lines from start (total: T lines, R remaining)]"
203
- const match = content.match(/^\[Reading (\d+) lines from (?:line )?(\d+|start) \(total: (\d+) lines/);
204
- if (!match)
205
- return undefined;
206
- const count = parseInt(match[1], 10);
207
- const from = match[2] === 'start' ? 1 : parseInt(match[2], 10);
208
- const total = parseInt(match[3], 10);
209
- return {
210
- fromLine: from,
211
- toLine: from + count - 1,
212
- totalLines: total,
213
- isPartial: count < total
214
- };
215
- }
216
- function renderBody(payload, htmlMode, startLine = 1) {
217
- const cleanedContent = stripReadStatusLine(payload.content);
218
- if (payload.fileType === 'image') {
219
- return renderImageBody(payload);
220
- }
221
- if (payload.fileType === 'unsupported') {
222
- return {
223
- notice: 'Preview is not available for this file type.',
224
- html: '<div class="panel-content source-content"></div>'
225
- };
226
- }
227
- if (payload.fileType === 'html') {
228
- return renderHtmlPreview(cleanedContent, htmlMode);
229
- }
230
- if (payload.fileType !== 'markdown') {
231
- const detectedLanguage = inferLanguageFromPath(payload.filePath);
232
- const formatted = formatJsonIfPossible(cleanedContent, payload.filePath);
233
- return {
234
- notice: formatted.notice,
235
- html: `<div class="panel-content source-content">${renderCodeViewer(formatted.content, detectedLanguage, startLine)}</div>`
236
- };
237
- }
238
- try {
239
- return {
240
- html: `<div class="panel-content markdown-content"><article class="markdown markdown-doc">${renderMarkdown(cleanedContent)}</article></div>`
241
- };
242
- }
243
- catch {
244
- return {
245
- notice: 'Markdown renderer failed. Showing raw source instead.',
246
- html: `<div class="panel-content source-content">${renderRawFallback(cleanedContent)}</div>`
247
- };
248
- }
249
- }
250
- function attachCopyHandler(payload) {
251
- const copyButton = document.getElementById('copy-source');
252
- if (!copyButton) {
253
- return;
254
- }
255
- const fallbackCopy = (text) => {
256
- const textArea = document.createElement('textarea');
257
- textArea.value = text;
258
- textArea.setAttribute('readonly', '');
259
- textArea.style.position = 'fixed';
260
- textArea.style.top = '-9999px';
261
- document.body.appendChild(textArea);
262
- textArea.select();
263
- const success = document.execCommand('copy');
264
- document.body.removeChild(textArea);
265
- return success;
266
- };
267
- const setButtonState = (label, revertMs) => {
268
- copyButton.setAttribute('title', label);
269
- copyButton.setAttribute('aria-label', label);
270
- copyButton.textContent = label;
271
- if (revertMs) {
272
- setTimeout(() => {
273
- copyButton.textContent = 'Copy';
274
- copyButton.setAttribute('title', 'Copy source');
275
- copyButton.setAttribute('aria-label', 'Copy source');
276
- }, revertMs);
277
- }
278
- };
279
- const copyTextData = async (text) => {
280
- try {
281
- if (navigator.clipboard?.writeText) {
282
- await navigator.clipboard.writeText(text);
283
- return true;
284
- }
285
- return fallbackCopy(text);
286
- }
287
- catch {
288
- return fallbackCopy(text);
289
- }
290
- };
291
- copyButton.addEventListener('click', async () => {
292
- trackUiEvent?.('copy_clicked', {
293
- file_type: payload.fileType,
294
- file_extension: getFileExtensionForAnalytics(payload.filePath)
295
- });
296
- const cleanedContent = stripReadStatusLine(payload.content);
297
- const copied = await copyTextData(cleanedContent);
298
- setButtonState(copied ? 'Copied!' : 'Copy failed', 1500);
299
- });
300
- }
301
- function attachHtmlToggleHandler(container, payload, htmlMode) {
302
- const toggleButton = document.getElementById('toggle-html-mode');
303
- if (!toggleButton || payload.fileType !== 'html') {
304
- return;
305
- }
306
- toggleButton.addEventListener('click', () => {
307
- const nextMode = htmlMode === 'rendered' ? 'source' : 'rendered';
308
- trackUiEvent?.('html_view_toggled', {
309
- file_type: payload.fileType,
310
- file_extension: getFileExtensionForAnalytics(payload.filePath)
311
- });
312
- renderApp(container, payload, nextMode, isExpanded);
313
- });
314
- }
315
- function attachOpenInFolderHandler(payload) {
316
- const openButton = document.getElementById('open-in-folder');
317
- if (!openButton) {
318
- return;
319
- }
320
- const command = buildOpenInFolderCommand(payload.filePath);
321
- if (!command) {
322
- openButton.disabled = true;
323
- return;
324
- }
325
- openButton.addEventListener('click', async () => {
326
- trackUiEvent?.('open_in_folder', {
327
- file_type: payload.fileType,
328
- file_extension: getFileExtensionForAnalytics(payload.filePath)
329
- });
330
- try {
331
- await rpcCallTool?.('start_process', {
332
- command,
333
- timeout_ms: 12000
334
- });
335
- }
336
- catch {
337
- // Keep UI stable if opening folder fails.
338
- }
339
- });
340
- }
341
- function attachLoadAllHandler(container, payload, htmlMode) {
342
- const beforeBtn = document.getElementById('load-before');
343
- const afterBtn = document.getElementById('load-after');
344
- if (!beforeBtn && !afterBtn) {
345
- return;
346
- }
347
- const range = parseReadRange(payload.content);
348
- if (!range?.isPartial)
349
- return;
350
- const currentContent = stripReadStatusLine(payload.content);
351
- const loadLines = async (btn, direction) => {
352
- const originalText = btn.textContent;
353
- btn.textContent = 'Loading…';
354
- btn.disabled = true;
355
- trackUiEvent?.(direction === 'before' ? 'load_lines_before' : 'load_lines_after', {
356
- file_type: payload.fileType,
357
- file_extension: getFileExtensionForAnalytics(payload.filePath)
358
- });
359
- try {
360
- // Load only the missing portion
361
- const readArgs = direction === 'before'
362
- ? { path: payload.filePath, offset: 0, length: range.fromLine - 1 }
363
- : { path: payload.filePath, offset: range.toLine };
364
- const result = await rpcCallTool?.('read_file', readArgs);
365
- const resultObj = result;
366
- const newText = resultObj?.content?.[0]?.text;
367
- if (newText && typeof newText === 'string') {
368
- const cleanNew = stripReadStatusLine(newText);
369
- // Merge: prepend or append the new lines
370
- const merged = direction === 'before'
371
- ? cleanNew + (cleanNew.endsWith('\n') ? '' : '\n') + currentContent
372
- : currentContent + (currentContent.endsWith('\n') ? '' : '\n') + cleanNew;
373
- // Build updated status line reflecting the new range
374
- const newFrom = direction === 'before' ? 1 : range.fromLine;
375
- const newTo = direction === 'after' ? range.totalLines : range.toLine;
376
- const lineCount = newTo - newFrom + 1;
377
- const remaining = range.totalLines - newTo;
378
- const isStillPartial = newFrom > 1 || newTo < range.totalLines;
379
- const statusLine = isStillPartial
380
- ? `[Reading ${lineCount} lines from ${newFrom === 1 ? 'start' : `line ${newFrom}`} (total: ${range.totalLines} lines, ${remaining} remaining)]\n`
381
- : '';
382
- const mergedPayload = {
383
- ...payload,
384
- content: statusLine + merged
385
- };
386
- renderApp(container, mergedPayload, htmlMode, isExpanded);
387
- }
388
- else {
389
- btn.textContent = 'Failed to load';
390
- setTimeout(() => { btn.textContent = originalText; btn.disabled = false; }, 2000);
391
- }
392
- }
393
- catch {
394
- btn.textContent = 'Failed to load';
395
- setTimeout(() => { btn.textContent = originalText; btn.disabled = false; }, 2000);
396
- }
397
- };
398
- beforeBtn?.addEventListener('click', () => void loadLines(beforeBtn, 'before'));
399
- afterBtn?.addEventListener('click', () => void loadLines(afterBtn, 'after'));
400
- }
401
- /**
402
- * Tracks native text selection and pushes it to the host via ui/update-model-context.
403
- *
404
- * How it works:
405
- * 1. User drags to select text anywhere in the preview (markdown, code, HTML).
406
- * 2. The selectionchange event fires; we extract the selected string.
407
- * 3. We call rpcUpdateContext() which sends a ui/update-model-context JSON-RPC
408
- * request to the host with the selected text + file path (+ line numbers for code).
409
- * 4. The host stores this as widget context.
410
- * 5. The LLM can access it by calling read_widget_context(tool_name="desktop-commander:read_file").
411
- *
412
- * Note: as of Feb 2025, Claude does NOT auto-inject ui/update-model-context into
413
- * the LLM's context window. The LLM must actively call read_widget_context to see
414
- * the selection. A floating tooltip near the selection tells the user this is working.
415
- */
416
- let selectionAbortController = null;
417
- function attachTextSelectionHandler(payload) {
418
- const contentWrapper = document.querySelector('.panel-content-wrapper');
419
- if (!contentWrapper)
420
- return;
421
- // Abort any previous selectionchange listener to avoid leaking listeners/closures
422
- if (selectionAbortController) {
423
- selectionAbortController.abort();
424
- selectionAbortController = null;
425
- }
426
- selectionAbortController = new AbortController();
427
- let hintEl = null;
428
- let lastSelectedText = '';
429
- let hideTimer = null;
430
- function positionHint(selection) {
431
- if (!hintEl)
432
- return;
433
- const range = selection.getRangeAt(0);
434
- const rect = range.getBoundingClientRect();
435
- const wrapperRect = contentWrapper.getBoundingClientRect();
436
- // Position above the selection, centered horizontally
437
- let left = rect.left + rect.width / 2 - wrapperRect.left;
438
- let top = rect.top - wrapperRect.top + contentWrapper.scrollTop - 32;
439
- // Clamp within wrapper bounds
440
- const hintWidth = hintEl.offsetWidth || 200;
441
- left = Math.max(8, Math.min(left - hintWidth / 2, contentWrapper.clientWidth - hintWidth - 8));
442
- top = Math.max(4, top);
443
- hintEl.style.left = `${left}px`;
444
- hintEl.style.top = `${top}px`;
445
- }
446
- function showHint(selection) {
447
- if (hideTimer) {
448
- clearTimeout(hideTimer);
449
- hideTimer = null;
450
- }
451
- if (!hintEl) {
452
- hintEl = document.createElement('div');
453
- hintEl.className = 'selection-hint';
454
- hintEl.textContent = 'AI can see your selection';
455
- contentWrapper.appendChild(hintEl);
456
- }
457
- hintEl.classList.add('visible');
458
- positionHint(selection);
459
- }
460
- function hideHint() {
461
- if (!hintEl)
462
- return;
463
- hintEl.classList.remove('visible');
464
- hideTimer = setTimeout(() => { hintEl?.remove(); hintEl = null; }, 200);
465
- }
466
- function getLineInfo(selection) {
467
- const anchorRow = selection.anchorNode?.parentElement?.closest('.code-line');
468
- const focusRow = selection.focusNode?.parentElement?.closest('.code-line');
469
- if (anchorRow && focusRow) {
470
- const a = parseInt(anchorRow.dataset.line ?? '', 10);
471
- const f = parseInt(focusRow.dataset.line ?? '', 10);
472
- if (!isNaN(a) && !isNaN(f)) {
473
- const low = Math.min(a, f);
474
- const high = Math.max(a, f);
475
- return low === high ? `line ${low}` : `lines ${low}–${high}`;
476
- }
477
- }
478
- return '';
479
- }
480
- document.addEventListener('selectionchange', () => {
481
- const selection = document.getSelection();
482
- if (!selection || selection.isCollapsed) {
483
- if (lastSelectedText) {
484
- lastSelectedText = '';
485
- rpcUpdateContext?.('');
486
- hideHint();
487
- }
488
- return;
489
- }
490
- const text = selection.toString().trim();
491
- if (!text || text === lastSelectedText)
492
- return;
493
- // Only act on selections within our content area
494
- const anchorInContent = contentWrapper.contains(selection.anchorNode);
495
- const focusInContent = contentWrapper.contains(selection.focusNode);
496
- if (!anchorInContent && !focusInContent) {
497
- if (lastSelectedText) {
498
- lastSelectedText = '';
499
- rpcUpdateContext?.('');
500
- hideHint();
501
- }
502
- return;
503
- }
504
- lastSelectedText = text;
505
- const lineInfo = getLineInfo(selection);
506
- const locationPart = lineInfo ? ` (${lineInfo})` : '';
507
- const context = `User selected text from file ${payload.filePath}${locationPart}:\n\`\`\`\n${text}\n\`\`\``;
508
- rpcUpdateContext?.(context);
509
- showHint(selection);
510
- trackUiEvent?.('text_selected', {
511
- file_type: payload.fileType,
512
- file_extension: getFileExtensionForAnalytics(payload.filePath),
513
- char_count: text.length
514
- });
515
- }, { signal: selectionAbortController.signal });
516
- }
517
- function renderStatusState(container, message) {
518
- container.innerHTML = `
519
- <main class="shell">
520
- <div class="compact-row compact-row--status">
521
- <span class="compact-label">${escapeHtml(message)}</span>
522
- </div>
523
- </main>
524
- `;
525
- document.body.classList.add('dc-ready');
526
- }
527
- function renderLoadingState(container) {
528
- container.innerHTML = `
529
- <main class="shell">
530
- <div class="compact-row compact-row--loading">
531
- <span class="compact-label">Preparing preview…</span>
532
- </div>
533
- </main>
534
- `;
535
- document.body.classList.add('dc-ready');
536
- }
537
- export function renderApp(container, payload, htmlMode = 'rendered', expandedState = false) {
538
- isExpanded = expandedState;
539
- shellController?.dispose();
540
- shellController = undefined;
541
- if (!payload) {
542
- renderStatusState(container, 'No preview available for this response.');
543
- onRender?.();
544
- return;
545
- }
546
- const canCopy = payload.fileType !== 'unsupported' && payload.fileType !== 'image';
547
- const canOpenInFolder = !isLikelyUrl(payload.filePath);
548
- const fileExtension = getFileExtensionForAnalytics(payload.filePath);
549
- const supportsPreview = payload.fileType !== 'unsupported';
550
- const range = parseReadRange(payload.content);
551
- const body = renderBody(payload, htmlMode, range?.fromLine ?? 1);
552
- const notice = body.notice ? `<div class="notice">${body.notice}</div>` : '';
553
- const breadcrumb = buildBreadcrumb(payload.filePath);
554
- const lineCount = range ? range.toLine - range.fromLine + 1 : countContentLines(payload.content);
555
- const fileTypeLabel = payload.fileType === 'markdown' ? 'MARKDOWN'
556
- : payload.fileType === 'html' ? 'HTML'
557
- : payload.fileType === 'image' ? 'IMAGE'
558
- : fileExtension !== 'none' ? fileExtension.toUpperCase()
559
- : 'TEXT';
560
- const compactLabel = range?.isPartial
561
- ? `View lines ${range.fromLine}–${range.toLine}`
562
- : 'View file';
563
- const footerLabel = range?.isPartial
564
- ? `${escapeHtml(fileTypeLabel)} • LINES ${range.fromLine}–${range.toLine} OF ${range.totalLines}`
565
- : `${escapeHtml(fileTypeLabel)} • ${lineCount} LINE${lineCount !== 1 ? 'S' : ''}`;
566
- const htmlToggle = payload.fileType === 'html'
567
- ? `<button class="panel-action" id="toggle-html-mode">${htmlMode === 'rendered' ? 'Source' : 'Rendered'}</button>`
568
- : '';
569
- const copyIcon = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>`;
570
- const folderIcon = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>`;
571
- // Content-area banners for missing lines
572
- const hasMissingBefore = range?.isPartial && range.fromLine > 1;
573
- const hasMissingAfter = range?.isPartial && range.toLine < range.totalLines && (range.totalLines - range.toLine) > 1;
574
- const loadBeforeBanner = hasMissingBefore
575
- ? `<button class="load-lines-banner" id="load-before">↑ Load lines 1–${range.fromLine - 1}</button>`
576
- : '';
577
- const loadAfterBanner = hasMissingAfter
578
- ? `<button class="load-lines-banner" id="load-after">↓ Load lines ${range.toLine + 1}–${range.totalLines}</button>`
579
- : '';
580
- container.innerHTML = `
581
- <main id="tool-shell" class="shell tool-shell ${isExpanded ? 'expanded' : 'collapsed'}">
582
- <div class="compact-row compact-row--ready" id="compact-toggle" role="button" tabindex="0" aria-expanded="${isExpanded}">
583
- <svg class="compact-chevron" viewBox="0 0 24 24" aria-hidden="true"><path d="M10 6l6 6-6 6z"/></svg>
584
- <span class="compact-label">${compactLabel}</span>
585
- <span class="compact-filename">${escapeHtml(payload.fileName)}</span>
586
- </div>
587
- <section class="panel">
588
- <div class="panel-topbar">
589
- <span class="panel-breadcrumb" title="${escapeHtml(payload.filePath)}">${breadcrumb}</span>
590
- <span class="panel-topbar-actions">
591
- ${htmlToggle}
592
- ${canOpenInFolder ? `<button class="panel-action" id="open-in-folder">${folderIcon} Open in folder</button>` : ''}
593
- ${canCopy && supportsPreview ? `<button class="panel-action" id="copy-source" title="Copy source" aria-label="Copy source">${copyIcon} Copy</button>` : ''}
594
- </span>
595
- </div>
596
- ${notice}
597
- <div class="panel-content-wrapper">
598
- ${loadBeforeBanner}
599
- ${body.html}
600
- ${loadAfterBanner}
601
- </div>
602
- <div class="panel-footer">
603
- <span>${footerLabel}</span>
604
- </div>
605
- </section>
606
- </main>
607
- `;
608
- document.body.classList.add('dc-ready');
609
- attachCopyHandler(payload);
610
- attachHtmlToggleHandler(container, payload, htmlMode);
611
- attachOpenInFolderHandler(payload);
612
- attachLoadAllHandler(container, payload, htmlMode);
613
- attachTextSelectionHandler(payload);
614
- // Compact row click toggles expand/collapse
615
- const compactRow = document.getElementById('compact-toggle');
616
- const handleCompactClick = () => {
617
- shellController?.toggle();
618
- };
619
- const handleCompactKeydown = (e) => {
620
- if (e.key === 'Enter' || e.key === ' ') {
621
- e.preventDefault();
622
- shellController?.toggle();
623
- }
624
- };
625
- compactRow?.addEventListener('click', handleCompactClick);
626
- compactRow?.addEventListener('keydown', handleCompactKeydown);
627
- shellController = createToolShellController({
628
- shell: document.getElementById('tool-shell'),
629
- toggleButton: null, // No separate toggle button; compact row handles it
630
- initialExpanded: isExpanded,
631
- onToggle: (expanded) => {
632
- isExpanded = expanded;
633
- compactRow?.setAttribute('aria-expanded', String(expanded));
634
- trackUiEvent?.(expanded ? 'expand' : 'collapse', {
635
- file_type: payload.fileType,
636
- file_extension: fileExtension
637
- });
638
- },
639
- onScrollAfterExpand: () => {
640
- trackUiEvent?.('scroll_after_expand', {
641
- file_type: payload.fileType,
642
- file_extension: fileExtension
643
- });
644
- },
645
- onRender
646
- });
647
- onRender?.();
648
- if (!previewShownFired) {
649
- previewShownFired = true;
650
- trackUiEvent?.('preview_shown', {
651
- file_type: payload.fileType,
652
- file_extension: fileExtension
653
- });
654
- }
655
- }
656
- export function bootstrapApp() {
657
- const container = document.getElementById('app');
658
- if (!container) {
659
- return;
660
- }
661
- renderLoadingState(container);
662
- const rpcClient = createWindowRpcClient({
663
- targetWindow: window.parent,
664
- timeoutMs: 15000,
665
- isTrustedSource: (source) => isTrustedParentMessageSource(source, window.parent)
666
- });
667
- const hostLifecycle = createUiHostLifecycle(rpcClient, {
668
- appName: 'Desktop Commander File Preview',
669
- appVersion: '1.0.0'
670
- });
671
- const themeAdapter = createUiThemeAdapter();
672
- rpcCallTool = (name, args) => (rpcClient.request('tools/call', {
673
- name,
674
- arguments: args
675
- }));
676
- rpcUpdateContext = (text) => {
677
- const params = text
678
- ? { content: [{ type: 'text', text }] }
679
- : { content: [] };
680
- rpcClient.request('ui/update-model-context', params).catch(() => {
681
- // Host may not support ui/update-model-context yet
682
- });
683
- };
684
- trackUiEvent = (event, params = {}) => {
685
- void rpcCallTool?.('track_ui_event', {
686
- event,
687
- component: 'file_preview',
688
- params: {
689
- tool_name: 'read_file',
690
- ...params
691
- }
692
- }).catch(() => {
693
- // Analytics failures should not impact UX.
694
- });
695
- };
696
- onRender = () => {
697
- hostLifecycle.notifyRender();
698
- };
699
- // ChatGPT widget state persistence (other hosts use standard ui/notifications/tool-result)
700
- const widgetState = createWidgetStateStorage(isPreviewStructuredContent);
701
- onRender?.();
702
- themeAdapter.applyFromData(window.__MCP_HOST_CONTEXT__);
703
- const renderAndSync = (payload) => {
704
- if (payload) {
705
- widgetState.write(payload); // Persist for refresh recovery (cross-host)
706
- }
707
- renderApp(container, payload, 'rendered', false);
708
- };
709
- let initialStateResolved = false;
710
- const resolveInitialState = (payload, message) => {
711
- if (initialStateResolved) {
712
- return;
713
- }
714
- initialStateResolved = true;
715
- if (payload) {
716
- renderAndSync(payload);
717
- return;
718
- }
719
- renderStatusState(container, message ?? 'No preview available for this response.');
720
- onRender?.();
721
- };
722
- // Try to restore from widget state first (ChatGPT only - survives refresh)
723
- const cachedPayload = widgetState.read();
724
- if (cachedPayload) {
725
- window.setTimeout(() => {
726
- resolveInitialState(cachedPayload);
727
- }, 50);
728
- }
729
- // Then check window globals
730
- const initialPayload = readStructuredContentFromWindow();
731
- if (initialPayload) {
732
- window.setTimeout(() => {
733
- resolveInitialState(initialPayload);
734
- }, 140);
735
- }
736
- // Timeout fallback: if no data arrives after retry, show helpful message
737
- window.setTimeout(() => {
738
- if (!initialStateResolved) {
739
- resolveInitialState(undefined, 'Preview unavailable after page refresh (known issue, fix in progress). Switch threads or re-run the tool.');
740
- }
741
- }, 8000);
742
- window.addEventListener('message', (event) => {
743
- try {
744
- if (rpcClient.handleMessageEvent(event)) {
745
- return;
746
- }
747
- if (!isTrustedParentMessageSource(event.source, window.parent)) {
748
- return;
749
- }
750
- if (!isObject(event.data)) {
751
- return;
752
- }
753
- themeAdapter.applyFromData(event.data);
754
- if (event.data.method === 'ui/notifications/tool-result') {
755
- const params = event.data.params;
756
- const candidate = isObject(params) && isObject(params.result) ? params.result : params;
757
- const payload = extractStructuredContent(candidate);
758
- const message = extractToolTextFromEvent(event.data) ?? extractToolText(candidate);
759
- if (!initialStateResolved) {
760
- if (payload) {
761
- renderLoadingState(container);
762
- onRender?.();
763
- window.setTimeout(() => resolveInitialState(payload), 120);
764
- return;
765
- }
766
- if (message) {
767
- resolveInitialState(undefined, message);
768
- }
769
- return;
770
- }
771
- if (payload) {
772
- renderAndSync(payload);
773
- }
774
- else if (message) {
775
- renderStatusState(container, message);
776
- onRender?.();
777
- }
778
- return;
779
- }
780
- const payload = extractStructuredContent(event.data);
781
- if (payload) {
782
- if (!initialStateResolved) {
783
- resolveInitialState(payload);
784
- return;
785
- }
786
- renderAndSync(payload);
787
- }
788
- }
789
- catch {
790
- renderStatusState(container, 'Preview failed to render.');
791
- onRender?.();
792
- }
793
- });
794
- hostLifecycle.observeResize();
795
- window.addEventListener('beforeunload', () => {
796
- shellController?.dispose();
797
- rpcClient.dispose();
798
- }, { once: true });
799
- hostLifecycle.initialize();
800
- }