@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
@@ -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>;