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