@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
@@ -0,0 +1,19 @@
1
+ export declare function shellQuote(value: string): string;
2
+ export declare function encodePowerShellCommand(script: string): string;
3
+ export declare function buildOpenInFolderCommand(filePath: string, isLikelyUrl: (filePath: string) => boolean): string | undefined;
4
+ export declare function buildOpenInEditorCommand(filePath: string, isLikelyUrl: (filePath: string) => boolean, editorAppCache: Map<string, {
5
+ appName: string;
6
+ appPath?: string;
7
+ }>): string | undefined;
8
+ export declare function detectDefaultMarkdownEditor(options: {
9
+ filePath: string;
10
+ editorAppCache: Map<string, {
11
+ appName: string;
12
+ appPath?: string;
13
+ }>;
14
+ editorAppPending: Set<string>;
15
+ callTool?: (name: string, args: Record<string, unknown>) => Promise<unknown | undefined>;
16
+ extractToolText: (value: unknown) => string | undefined;
17
+ onDetected?: () => void;
18
+ }): Promise<void>;
19
+ export declare function renderMarkdownEditorAppIcon(): string;
@@ -0,0 +1,94 @@
1
+ import { getParentDirectory } from '../path-utils.js';
2
+ export function shellQuote(value) {
3
+ return `'${value.replace(/'/g, `'\\''`)}'`;
4
+ }
5
+ export function encodePowerShellCommand(script) {
6
+ const utf16leBytes = [];
7
+ for (let index = 0; index < script.length; index += 1) {
8
+ const codeUnit = script.charCodeAt(index);
9
+ utf16leBytes.push(codeUnit & 0xff, codeUnit >> 8);
10
+ }
11
+ let binary = '';
12
+ for (const byte of utf16leBytes) {
13
+ binary += String.fromCharCode(byte);
14
+ }
15
+ return btoa(binary);
16
+ }
17
+ export function buildOpenInFolderCommand(filePath, isLikelyUrl) {
18
+ const trimmedPath = filePath.trim();
19
+ if (!trimmedPath || isLikelyUrl(trimmedPath)) {
20
+ return undefined;
21
+ }
22
+ const userAgent = navigator.userAgent.toLowerCase();
23
+ if (userAgent.includes('win')) {
24
+ const escapedForPowerShell = trimmedPath.replace(/'/g, "''");
25
+ const script = `Start-Process -FilePath explorer.exe -ArgumentList @('/select,','${escapedForPowerShell}')`;
26
+ return `powershell.exe -NoProfile -NonInteractive -EncodedCommand ${encodePowerShellCommand(script)}`;
27
+ }
28
+ if (userAgent.includes('mac')) {
29
+ return `open -R ${shellQuote(trimmedPath)}`;
30
+ }
31
+ return `xdg-open ${shellQuote(getParentDirectory(trimmedPath))}`;
32
+ }
33
+ export function buildOpenInEditorCommand(filePath, isLikelyUrl, editorAppCache) {
34
+ const trimmedPath = filePath.trim();
35
+ if (!trimmedPath || isLikelyUrl(trimmedPath)) {
36
+ return undefined;
37
+ }
38
+ const cachedApp = editorAppCache.get(trimmedPath);
39
+ if (cachedApp?.appPath && navigator.userAgent.toLowerCase().includes('mac')) {
40
+ return `open -a ${shellQuote(cachedApp.appPath)} ${shellQuote(trimmedPath)}`;
41
+ }
42
+ const userAgent = navigator.userAgent.toLowerCase();
43
+ if (userAgent.includes('win')) {
44
+ const escapedForPowerShell = trimmedPath.replace(/'/g, "''");
45
+ const script = `Start-Process -FilePath '${escapedForPowerShell}'`;
46
+ return `powershell.exe -NoProfile -NonInteractive -EncodedCommand ${encodePowerShellCommand(script)}`;
47
+ }
48
+ if (userAgent.includes('mac')) {
49
+ return `open ${shellQuote(trimmedPath)}`;
50
+ }
51
+ return `xdg-open ${shellQuote(trimmedPath)}`;
52
+ }
53
+ export async function detectDefaultMarkdownEditor(options) {
54
+ const trimmedPath = options.filePath.trim();
55
+ if (!trimmedPath || options.editorAppCache.has(trimmedPath) || options.editorAppPending.has(trimmedPath)) {
56
+ return;
57
+ }
58
+ const userAgent = navigator.userAgent.toLowerCase();
59
+ if (!userAgent.includes('mac')) {
60
+ return;
61
+ }
62
+ options.editorAppPending.add(trimmedPath);
63
+ try {
64
+ const detectCommand = `osascript -e ${shellQuote(`set appAlias to default application of (info for POSIX file "${trimmedPath.replace(/"/g, '\\"')}")
65
+ return (name of (info for appAlias)) & linefeed & POSIX path of appAlias`)}`;
66
+ const detectResult = await options.callTool?.('start_process', {
67
+ command: detectCommand,
68
+ timeout_ms: 12000,
69
+ });
70
+ const text = options.extractToolText(detectResult) ?? '';
71
+ if (!text || text.toLowerCase().includes('error') || text.toLowerCase().includes('execution')) {
72
+ return;
73
+ }
74
+ const lines = text.split('\n').map((line) => line.trim()).filter(Boolean);
75
+ const appName = lines[lines.length - 2]?.replace(/\.app$/i, '') ?? '';
76
+ const appPath = lines[lines.length - 1] ?? '';
77
+ if (appName && appPath.startsWith('/')) {
78
+ options.editorAppCache.set(trimmedPath, {
79
+ appName,
80
+ appPath,
81
+ });
82
+ options.onDetected?.();
83
+ }
84
+ }
85
+ catch {
86
+ // Fall back to generic editor label.
87
+ }
88
+ finally {
89
+ options.editorAppPending.delete(trimmedPath);
90
+ }
91
+ }
92
+ export function renderMarkdownEditorAppIcon() {
93
+ return '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 1 1 3 3L7 19l-4 1 1-4Z"/></svg>';
94
+ }
@@ -0,0 +1,9 @@
1
+ import type { RenderPayload } from '../model.js';
2
+ export declare function attachSelectionContext(options: {
3
+ payload: RenderPayload;
4
+ isMarkdownEditing: boolean;
5
+ updateContext?: (text: string) => void;
6
+ trackUiEvent?: (event: string, params?: Record<string, unknown>) => void;
7
+ getFileExtensionForAnalytics: (filePath: string) => string;
8
+ previousAbortController: AbortController | null;
9
+ }): AbortController | null;
@@ -0,0 +1,106 @@
1
+ export function attachSelectionContext(options) {
2
+ if (options.isMarkdownEditing) {
3
+ if (options.previousAbortController) {
4
+ options.previousAbortController.abort();
5
+ }
6
+ return null;
7
+ }
8
+ const contentWrapper = document.querySelector('.panel-content-wrapper');
9
+ if (!contentWrapper) {
10
+ return options.previousAbortController;
11
+ }
12
+ const wrapper = contentWrapper;
13
+ options.previousAbortController?.abort();
14
+ const abortController = new AbortController();
15
+ let hintEl = null;
16
+ let lastSelectedText = '';
17
+ let hideTimer = null;
18
+ function positionHint(selection) {
19
+ if (!hintEl)
20
+ return;
21
+ const range = selection.getRangeAt(0);
22
+ const rect = range.getBoundingClientRect();
23
+ const wrapperRect = wrapper.getBoundingClientRect();
24
+ let left = rect.left + rect.width / 2 - wrapperRect.left;
25
+ let top = rect.top - wrapperRect.top + wrapper.scrollTop - 32;
26
+ const hintWidth = hintEl.offsetWidth || 200;
27
+ left = Math.max(8, Math.min(left - hintWidth / 2, wrapper.clientWidth - hintWidth - 8));
28
+ top = Math.max(4, top);
29
+ hintEl.style.left = `${left}px`;
30
+ hintEl.style.top = `${top}px`;
31
+ }
32
+ function showHint(selection) {
33
+ if (hideTimer) {
34
+ clearTimeout(hideTimer);
35
+ hideTimer = null;
36
+ }
37
+ if (!hintEl) {
38
+ hintEl = document.createElement('div');
39
+ hintEl.className = 'selection-hint';
40
+ hintEl.textContent = 'AI can see your selection';
41
+ wrapper.appendChild(hintEl);
42
+ }
43
+ hintEl.classList.add('visible');
44
+ positionHint(selection);
45
+ }
46
+ function hideHint() {
47
+ if (!hintEl)
48
+ return;
49
+ hintEl.classList.remove('visible');
50
+ hideTimer = setTimeout(() => {
51
+ hintEl?.remove();
52
+ hintEl = null;
53
+ }, 200);
54
+ }
55
+ function getLineInfo(selection) {
56
+ const anchorRow = selection.anchorNode?.parentElement?.closest('.code-line');
57
+ const focusRow = selection.focusNode?.parentElement?.closest('.code-line');
58
+ if (anchorRow && focusRow) {
59
+ const anchorLine = parseInt(anchorRow.dataset.line ?? '', 10);
60
+ const focusLine = parseInt(focusRow.dataset.line ?? '', 10);
61
+ if (!isNaN(anchorLine) && !isNaN(focusLine)) {
62
+ const low = Math.min(anchorLine, focusLine);
63
+ const high = Math.max(anchorLine, focusLine);
64
+ return low === high ? `line ${low}` : `lines ${low}–${high}`;
65
+ }
66
+ }
67
+ return '';
68
+ }
69
+ document.addEventListener('selectionchange', () => {
70
+ const selection = document.getSelection();
71
+ if (!selection || selection.isCollapsed) {
72
+ if (lastSelectedText) {
73
+ lastSelectedText = '';
74
+ options.updateContext?.('');
75
+ hideHint();
76
+ }
77
+ return;
78
+ }
79
+ const text = selection.toString().trim();
80
+ if (!text || text === lastSelectedText) {
81
+ return;
82
+ }
83
+ const anchorInContent = wrapper.contains(selection.anchorNode);
84
+ const focusInContent = wrapper.contains(selection.focusNode);
85
+ if (!anchorInContent && !focusInContent) {
86
+ if (lastSelectedText) {
87
+ lastSelectedText = '';
88
+ options.updateContext?.('');
89
+ hideHint();
90
+ }
91
+ return;
92
+ }
93
+ lastSelectedText = text;
94
+ const lineInfo = getLineInfo(selection);
95
+ const locationPart = lineInfo ? ` (${lineInfo})` : '';
96
+ const context = `User selected text from file ${options.payload.filePath}${locationPart}:\n\`\`\`\n${text}\n\`\`\``;
97
+ options.updateContext?.(context);
98
+ showHint(selection);
99
+ options.trackUiEvent?.('text_selected', {
100
+ file_type: options.payload.fileType,
101
+ file_extension: options.getFileExtensionForAnalytics(options.payload.filePath),
102
+ char_count: text.length,
103
+ });
104
+ }, { signal: abortController.signal });
105
+ return abortController;
106
+ }
@@ -0,0 +1,25 @@
1
+ export interface Block {
2
+ start: number;
3
+ end: number;
4
+ text: string;
5
+ }
6
+ /**
7
+ * Split markdown source into top-level blocks with source ranges. The ranges
8
+ * drive byte-exact preservation of untouched content when merging Milkdown's
9
+ * re-serialized output back into the original on-disk source.
10
+ */
11
+ export declare function extractBlocks(source: string): Block[];
12
+ export interface MergeReport {
13
+ merged: string;
14
+ preservedCount: number;
15
+ rewrittenCount: number;
16
+ /** Populated when block counts don't align and we fell back to the full output. */
17
+ fallback?: string;
18
+ }
19
+ /**
20
+ * Merge Milkdown's current serialization back into the original on-disk source
21
+ * block-by-block. Blocks whose Milkdown representation is unchanged since mount
22
+ * are emitted byte-identical to disk; edited blocks take Milkdown's output.
23
+ * Separators between blocks come from the original source.
24
+ */
25
+ export declare function mergeBlocks(originalSource: string, originalBlocks: Block[], baselineBlocks: Block[], currentSerialization: string, currentBlocks: Block[]): MergeReport;
@@ -0,0 +1,86 @@
1
+ // markdown-it ships without TypeScript typings in this setup; reuse the
2
+ // existing ambient-import pattern from parser.ts.
3
+ // @ts-expect-error markdown-it does not provide local TypeScript typings in this setup.
4
+ import MarkdownIt from 'markdown-it';
5
+ const parser = new MarkdownIt({ html: true });
6
+ /**
7
+ * Split markdown source into top-level blocks with source ranges. The ranges
8
+ * drive byte-exact preservation of untouched content when merging Milkdown's
9
+ * re-serialized output back into the original on-disk source.
10
+ */
11
+ export function extractBlocks(source) {
12
+ const tokens = parser.parse(source, {});
13
+ const lines = source.split('\n');
14
+ const lineOffsets = [0];
15
+ for (let i = 0; i < lines.length; i++) {
16
+ lineOffsets.push(lineOffsets[i] + lines[i].length + 1);
17
+ }
18
+ const blocks = [];
19
+ let lastEndLine = 0;
20
+ for (const token of tokens) {
21
+ if (!token.map || token.map.length < 2)
22
+ continue;
23
+ const [startLine, endLine] = token.map;
24
+ const t = token.type;
25
+ const isOpening = typeof t === 'string' && (t.endsWith('_open')
26
+ || t === 'hr'
27
+ || t === 'fence'
28
+ || t === 'code_block'
29
+ || t === 'html_block');
30
+ if (!isOpening || startLine < lastEndLine)
31
+ continue;
32
+ const start = lineOffsets[startLine];
33
+ const rawEnd = lineOffsets[endLine] ?? source.length;
34
+ const end = Math.min(source.length, Math.max(start, rawEnd - 1));
35
+ blocks.push({ start, end, text: source.slice(start, end) });
36
+ lastEndLine = endLine;
37
+ }
38
+ return blocks;
39
+ }
40
+ /**
41
+ * Merge Milkdown's current serialization back into the original on-disk source
42
+ * block-by-block. Blocks whose Milkdown representation is unchanged since mount
43
+ * are emitted byte-identical to disk; edited blocks take Milkdown's output.
44
+ * Separators between blocks come from the original source.
45
+ */
46
+ export function mergeBlocks(originalSource, originalBlocks, baselineBlocks, currentSerialization, currentBlocks) {
47
+ if (originalBlocks.length !== baselineBlocks.length) {
48
+ return {
49
+ merged: currentSerialization,
50
+ preservedCount: 0,
51
+ rewrittenCount: currentBlocks.length,
52
+ fallback: `original parses to ${originalBlocks.length} blocks but baseline parses to ${baselineBlocks.length}`,
53
+ };
54
+ }
55
+ if (baselineBlocks.length !== currentBlocks.length) {
56
+ return {
57
+ merged: currentSerialization,
58
+ preservedCount: 0,
59
+ rewrittenCount: currentBlocks.length,
60
+ fallback: `block count changed (baseline=${baselineBlocks.length}, current=${currentBlocks.length})`,
61
+ };
62
+ }
63
+ const parts = [];
64
+ let preserved = 0;
65
+ let rewritten = 0;
66
+ parts.push(originalSource.slice(0, originalBlocks[0]?.start ?? 0));
67
+ for (let i = 0; i < originalBlocks.length; i++) {
68
+ if (baselineBlocks[i].text === currentBlocks[i].text) {
69
+ parts.push(originalBlocks[i].text);
70
+ preserved++;
71
+ }
72
+ else {
73
+ parts.push(currentBlocks[i].text);
74
+ rewritten++;
75
+ }
76
+ const nextStart = i + 1 < originalBlocks.length
77
+ ? originalBlocks[i + 1].start
78
+ : originalSource.length;
79
+ parts.push(originalSource.slice(originalBlocks[i].end, nextStart));
80
+ }
81
+ return {
82
+ merged: parts.join(''),
83
+ preservedCount: preserved,
84
+ rewrittenCount: rewritten,
85
+ };
86
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * The "file changed on disk" conflict resolver.
3
+ *
4
+ * Shown when saveDocument detected that disk differs from what the editor
5
+ * thought it had. The editor has already re-synced its sourceContent to the
6
+ * fresh disk content with keepDraft: true — so the dialog's two actions map
7
+ * onto concrete state transitions:
8
+ *
9
+ * "Use disk version" — replace the draft with disk content
10
+ * (syncStateFromContent without keepDraft).
11
+ * Destroys unsaved edits.
12
+ *
13
+ * "Save my changes" — close the dialog and re-run saveDocument.
14
+ * computeEditBlocks will now diff against the fresh
15
+ * disk content, so non-overlapping edits merge in
16
+ * and overlapping edits win over disk for the
17
+ * lines the user actually touched.
18
+ *
19
+ * The dialog is modal (dimmed backdrop, keyboard-trapped, click-outside does
20
+ * not dismiss). Escape and the ✕ button both close it without taking either
21
+ * action — equivalent to "I'll deal with this later"; the save button stays
22
+ * dirty so the user can retry or keep editing.
23
+ */
24
+ export interface OpenConflictDialogOptions {
25
+ fileName: string;
26
+ onUseDiskVersion: () => void;
27
+ onSaveMyChanges: () => void;
28
+ onCancel?: () => void;
29
+ }
30
+ export interface ConflictDialogController {
31
+ open: (options: OpenConflictDialogOptions) => void;
32
+ close: () => void;
33
+ isOpen: () => boolean;
34
+ }
35
+ export declare function renderConflictDialogMarkup(): string;
36
+ interface CreateConflictDialogOptions {
37
+ container: ParentNode;
38
+ }
39
+ export declare function createConflictDialogController(options: CreateConflictDialogOptions): ConflictDialogController;
40
+ export {};
@@ -0,0 +1,163 @@
1
+ /**
2
+ * The "file changed on disk" conflict resolver.
3
+ *
4
+ * Shown when saveDocument detected that disk differs from what the editor
5
+ * thought it had. The editor has already re-synced its sourceContent to the
6
+ * fresh disk content with keepDraft: true — so the dialog's two actions map
7
+ * onto concrete state transitions:
8
+ *
9
+ * "Use disk version" — replace the draft with disk content
10
+ * (syncStateFromContent without keepDraft).
11
+ * Destroys unsaved edits.
12
+ *
13
+ * "Save my changes" — close the dialog and re-run saveDocument.
14
+ * computeEditBlocks will now diff against the fresh
15
+ * disk content, so non-overlapping edits merge in
16
+ * and overlapping edits win over disk for the
17
+ * lines the user actually touched.
18
+ *
19
+ * The dialog is modal (dimmed backdrop, keyboard-trapped, click-outside does
20
+ * not dismiss). Escape and the ✕ button both close it without taking either
21
+ * action — equivalent to "I'll deal with this later"; the save button stays
22
+ * dirty so the user can retry or keep editing.
23
+ */
24
+ export function renderConflictDialogMarkup() {
25
+ return `
26
+ <div class="md-conflict-modal" id="md-conflict-modal" role="dialog" aria-modal="true" aria-labelledby="md-conflict-title" aria-describedby="md-conflict-body" hidden>
27
+ <div class="md-conflict-card">
28
+ <header class="md-conflict-header">
29
+ <h3 id="md-conflict-title">⚠ This file changed on disk</h3>
30
+ <button type="button" class="md-conflict-close" id="md-conflict-close" aria-label="Close">
31
+ <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
32
+ <path d="M7 7l10 10M17 7L7 17" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
33
+ </svg>
34
+ </button>
35
+ </header>
36
+ <div class="md-conflict-body" id="md-conflict-body">
37
+ <p>
38
+ Something else modified
39
+ <strong class="md-conflict-filename" id="md-conflict-filename"></strong>
40
+ while you were editing. Your unsaved edits are preserved.
41
+ </p>
42
+ <p>If you save now:</p>
43
+ <ul>
44
+ <li>Changes you made to lines the external edit didn't touch will be saved alongside the external changes.</li>
45
+ <li>Changes you made to lines that also changed externally will overwrite the external version on those lines.</li>
46
+ </ul>
47
+ </div>
48
+ <footer class="md-conflict-footer">
49
+ <button type="button" class="md-conflict-btn md-conflict-btn--secondary" id="md-conflict-use-disk">
50
+ Use disk version
51
+ </button>
52
+ <button type="button" class="md-conflict-btn md-conflict-btn--primary" id="md-conflict-save-mine">
53
+ Save my changes
54
+ </button>
55
+ </footer>
56
+ </div>
57
+ </div>
58
+ `;
59
+ }
60
+ export function createConflictDialogController(options) {
61
+ const { container } = options;
62
+ const modal = container.querySelector('#md-conflict-modal');
63
+ const filenameEl = container.querySelector('#md-conflict-filename');
64
+ const useDiskBtn = container.querySelector('#md-conflict-use-disk');
65
+ const saveMineBtn = container.querySelector('#md-conflict-save-mine');
66
+ const closeBtn = container.querySelector('#md-conflict-close');
67
+ let currentOptions = null;
68
+ let previousActiveElement = null;
69
+ const close = () => {
70
+ if (!modal || modal.hidden) {
71
+ return;
72
+ }
73
+ modal.hidden = true;
74
+ document.removeEventListener('keydown', handleKeyDown, true);
75
+ modal.removeEventListener('click', handleBackdropClick);
76
+ const cancel = currentOptions?.onCancel;
77
+ currentOptions = null;
78
+ // Restore focus to whatever the user was on before the dialog opened.
79
+ if (previousActiveElement && document.contains(previousActiveElement)) {
80
+ try {
81
+ previousActiveElement.focus();
82
+ }
83
+ catch {
84
+ /* focus can throw on removed nodes — ignore */
85
+ }
86
+ }
87
+ previousActiveElement = null;
88
+ cancel?.();
89
+ };
90
+ const handleKeyDown = (event) => {
91
+ if (!modal || modal.hidden) {
92
+ return;
93
+ }
94
+ if (event.key === 'Escape') {
95
+ event.stopPropagation();
96
+ event.preventDefault();
97
+ close();
98
+ return;
99
+ }
100
+ if (event.key === 'Tab') {
101
+ // Minimal focus trap between the three buttons.
102
+ const focusable = [useDiskBtn, saveMineBtn, closeBtn].filter((el) => !!el);
103
+ if (focusable.length === 0)
104
+ return;
105
+ const active = document.activeElement;
106
+ const currentIndex = active ? focusable.indexOf(active) : -1;
107
+ const direction = event.shiftKey ? -1 : 1;
108
+ const nextIndex = currentIndex === -1
109
+ ? (direction === 1 ? 0 : focusable.length - 1)
110
+ : (currentIndex + direction + focusable.length) % focusable.length;
111
+ event.preventDefault();
112
+ focusable[nextIndex].focus();
113
+ }
114
+ };
115
+ const handleBackdropClick = (event) => {
116
+ // Click on the dimmed backdrop (the modal element itself, not the card)
117
+ // is deliberately not a dismiss — the user must make a choice or hit ✕.
118
+ if (event.target === modal) {
119
+ event.stopPropagation();
120
+ }
121
+ };
122
+ const handleUseDisk = () => {
123
+ const cb = currentOptions?.onUseDiskVersion;
124
+ // Clear currentOptions first so close() doesn't also fire onCancel.
125
+ currentOptions = null;
126
+ close();
127
+ cb?.();
128
+ };
129
+ const handleSaveMine = () => {
130
+ const cb = currentOptions?.onSaveMyChanges;
131
+ currentOptions = null;
132
+ close();
133
+ cb?.();
134
+ };
135
+ useDiskBtn?.addEventListener('click', handleUseDisk);
136
+ saveMineBtn?.addEventListener('click', handleSaveMine);
137
+ closeBtn?.addEventListener('click', close);
138
+ return {
139
+ open: (options) => {
140
+ if (!modal) {
141
+ // No-op if the markup wasn't injected — fall back to cancel callback
142
+ // so the editor can still notify the user via the inline path.
143
+ options.onCancel?.();
144
+ return;
145
+ }
146
+ currentOptions = options;
147
+ if (filenameEl) {
148
+ filenameEl.textContent = options.fileName;
149
+ }
150
+ previousActiveElement = document.activeElement ?? null;
151
+ modal.hidden = false;
152
+ document.addEventListener('keydown', handleKeyDown, true);
153
+ modal.addEventListener('click', handleBackdropClick);
154
+ // Default focus goes to the safer action ("Save my changes" is the
155
+ // non-destructive intent — it doesn't discard the user's draft).
156
+ window.requestAnimationFrame(() => {
157
+ saveMineBtn?.focus();
158
+ });
159
+ },
160
+ close,
161
+ isOpen: () => !!modal && !modal.hidden,
162
+ };
163
+ }
@@ -0,0 +1,38 @@
1
+ import type { MarkdownWorkspaceState, RenderBodyResult, RenderPayload } from '../model.js';
2
+ import { type MarkdownEditorView } from './editor.js';
3
+ import type { OpenConflictDialogOptions } from './conflict-dialog.js';
4
+ export interface MarkdownControllerDependencies {
5
+ callTool?: (name: string, args: Record<string, unknown>) => Promise<unknown | undefined>;
6
+ openExternalLink?: (url: string) => Promise<boolean | undefined>;
7
+ requestDisplayMode?: (mode: 'inline' | 'fullscreen') => Promise<string | null | undefined>;
8
+ getAvailableDisplayModes: () => string[];
9
+ getCurrentDisplayMode: () => string | null;
10
+ getCurrentPayload: () => RenderPayload | undefined;
11
+ setExpanded: (expanded: boolean) => void;
12
+ syncPayload?: (payload?: RenderPayload) => void;
13
+ storePayloadOverride: (payload: RenderPayload) => void;
14
+ rerender: () => void;
15
+ updateSaveStatus: (label: string, statusClass: string) => void;
16
+ trackUiEvent?: (event: string, params?: Record<string, unknown>) => void;
17
+ showConflictDialog?: (options: OpenConflictDialogOptions) => void;
18
+ }
19
+ export declare function createMarkdownController(dependencies: MarkdownControllerDependencies): {
20
+ attachHandlers: (payload: RenderPayload) => void;
21
+ buildBody: (payload: RenderPayload) => RenderBodyResult;
22
+ clear: () => void;
23
+ disposeHandles: () => void;
24
+ ensureCompletePayload: (payload: RenderPayload) => Promise<RenderPayload>;
25
+ getCopyText: (payload: RenderPayload) => string | null;
26
+ getState: (payload: RenderPayload) => MarkdownWorkspaceState;
27
+ handleInlineExitFromFullscreen: (originalPayload?: RenderPayload) => Promise<RenderPayload | undefined>;
28
+ isUndoAvailable: (state: MarkdownWorkspaceState) => boolean;
29
+ readCompletePayload: (filePath: string) => Promise<RenderPayload | null>;
30
+ readPayload: (filePath: string, length?: number, offset?: number) => Promise<RenderPayload | null>;
31
+ readPayloadContent: (payload: RenderPayload) => string;
32
+ refreshFromDisk: (payload: RenderPayload) => Promise<void>;
33
+ requestEditMode: (payload: RenderPayload) => Promise<void>;
34
+ requestFullscreen: () => Promise<boolean>;
35
+ saveDocument: () => Promise<void>;
36
+ setEditorView: (payload: RenderPayload, view: MarkdownEditorView) => void;
37
+ };
38
+ export type MarkdownController = ReturnType<typeof createMarkdownController>;