@kabmo-labs/kabmo 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/README.md +7 -0
  2. package/dist/client/index.html +1 -1
  3. package/dist/client/index.js +403 -384
  4. package/dist/client/static/js/{index-0wvbca0b.js → index-bpptfkz2.js} +905 -875
  5. package/dist/client/static/js/index-k315p1e8.css +1 -0
  6. package/package.json +10 -1
  7. package/src/client/components/common/code-surface/documents.test.ts +120 -0
  8. package/src/client/components/common/code-surface/documents.ts +201 -0
  9. package/src/client/components/common/code-surface/extensions.test.ts +110 -0
  10. package/src/client/components/common/code-surface/extensions.ts +162 -0
  11. package/src/client/components/common/code-surface/handle.ts +102 -0
  12. package/src/client/components/common/code-surface/index.tsx +253 -314
  13. package/src/client/components/common/code-surface/keymap.test.ts +133 -0
  14. package/src/client/components/common/code-surface/keymap.ts +267 -0
  15. package/src/client/components/common/code-surface/marks.ts +74 -0
  16. package/src/client/components/common/code-surface/shiki.ts +234 -0
  17. package/src/client/components/common/code-surface/sync.test.ts +185 -0
  18. package/src/client/components/common/code-surface/sync.ts +58 -0
  19. package/src/client/components/common/code-surface/theme.test.ts +202 -0
  20. package/src/client/components/common/code-surface/theme.ts +111 -0
  21. package/src/client/components/common/editor-view-buttons/index.test.tsx +148 -0
  22. package/src/client/components/common/editor-view-buttons/index.tsx +109 -0
  23. package/src/client/components/common/header-controls/index.tsx +24 -1
  24. package/src/client/components/common/header-controls/shell-chrome.test.tsx +272 -0
  25. package/src/client/components/common/shell-update-button/Modal.tsx +163 -0
  26. package/src/client/components/common/shell-update-button/index.test.tsx +251 -0
  27. package/src/client/components/common/shell-update-button/index.tsx +125 -0
  28. package/src/client/components/common/toolbar-row/index.test.tsx +166 -0
  29. package/src/client/components/common/toolbar-row/index.tsx +189 -0
  30. package/src/client/components/common/workspace-options-menu/index.tsx +19 -1
  31. package/src/client/components/layout/desktop-layout/TopNavbar.tsx +5 -6
  32. package/src/client/components/layout/desktop-layout/WorkspacePanels.tsx +41 -78
  33. package/src/client/components/layout/desktop-layout/index.tsx +55 -69
  34. package/src/client/components/layout/desktop-layout/resizer/index.tsx +6 -3
  35. package/src/client/components/layout/session-sidebar/CategoryHeader.tsx +24 -0
  36. package/src/client/components/layout/session-sidebar/CategoryHeader.worktree.test.tsx +126 -0
  37. package/src/client/components/layout/session-sidebar/CategoryItem.tsx +4 -0
  38. package/src/client/components/layout/session-sidebar/Footer.tsx +8 -15
  39. package/src/client/components/layout/session-sidebar/SessionItem.tsx +12 -0
  40. package/src/client/components/layout/session-sidebar/SessionList.tsx +4 -0
  41. package/src/client/components/layout/session-sidebar/SessionsView.tsx +24 -0
  42. package/src/client/components/layout/session-sidebar/WorktreeBadge.test.ts +48 -0
  43. package/src/client/components/layout/session-sidebar/WorktreeBadge.tsx +55 -0
  44. package/src/client/components/mobile/LayoutWrapper.tsx +23 -16
  45. package/src/client/components/mobile/RightSidebar.tsx +21 -10
  46. package/src/client/components/mobile/SessionSidebar.tsx +8 -0
  47. package/src/client/components/mobile/header-titlebar.test.tsx +172 -0
  48. package/src/client/components/mobile/mobile-main-view/Header.tsx +10 -1
  49. package/src/client/components/mobile/mobile-right-sidebar/FullDiff.tsx +3 -0
  50. package/src/client/components/mobile/mobile-right-sidebar/FullEditor.tsx +63 -38
  51. package/src/client/components/mobile/mobile-right-sidebar/OutlineButton.test.tsx +137 -0
  52. package/src/client/components/mobile/mobile-right-sidebar/OutlineButton.tsx +14 -3
  53. package/src/client/components/mobile/mobile-session-sidebar/Footer.tsx +9 -21
  54. package/src/client/components/mobile/mobile-session-sidebar/Header.tsx +6 -2
  55. package/src/client/components/mobile/mobile-session-sidebar/Item.tsx +16 -0
  56. package/src/client/components/mobile/mobile-session-sidebar/List.tsx +4 -0
  57. package/src/client/components/mobile/mobile-session-sidebar/SessionRow.tsx +5 -0
  58. package/src/client/components/mobile/mobile-session-sidebar/WorktreeDialog.tsx +49 -0
  59. package/src/client/components/mobile/worktree-session.ts +51 -0
  60. package/src/client/components/settings/Modal.tsx +8 -0
  61. package/src/client/components/settings/categories/AppearanceSettings.tsx +3 -0
  62. package/src/client/components/settings/categories/ProjectSettings.tsx +22 -8
  63. package/src/client/components/settings/categories/appearance-settings/EditorThemeSection.test.tsx +167 -0
  64. package/src/client/components/settings/categories/appearance-settings/EditorThemeSection.tsx +184 -0
  65. package/src/client/components/settings/categories/project-settings/WorktreeSettings.tsx +146 -0
  66. package/src/client/components/settings/categories/project-settings/worktree-row.test.ts +83 -0
  67. package/src/client/components/settings/categories/project-settings/worktree-row.ts +47 -0
  68. package/src/client/components/workspace/chat-timeline/EmptyWorkspacePrompt.tsx +36 -55
  69. package/src/client/components/workspace/chat-timeline/PendingChatView.tsx +8 -0
  70. package/src/client/components/workspace/chat-timeline/SystemNotice.tsx +9 -4
  71. package/src/client/components/workspace/chat-timeline/TaskResultContent.tsx +9 -7
  72. package/src/client/components/workspace/chat-timeline/index.tsx +5 -0
  73. package/src/client/components/workspace/chat-timeline/target-picker/WorkspacePicker.test.tsx +132 -0
  74. package/src/client/components/workspace/chat-timeline/target-picker/WorkspacePicker.tsx +120 -0
  75. package/src/client/components/workspace/chat-timeline/target-picker/WorktreePicker.test.tsx +319 -0
  76. package/src/client/components/workspace/chat-timeline/target-picker/WorktreePicker.tsx +285 -0
  77. package/src/client/components/workspace/chat-timeline/tool-renderers/ask-panel/index.test.ts +2 -0
  78. package/src/client/components/workspace/chat-timeline/tool-renderers/hashline-patch/index.tsx +34 -29
  79. package/src/client/components/workspace/chat-timeline/tool-renderers/panels/AstEdit.tsx +11 -9
  80. package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Bash.tsx +10 -7
  81. package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Edit.tsx +25 -8
  82. package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Eval.test.tsx +146 -0
  83. package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Eval.tsx +32 -17
  84. package/src/client/components/workspace/chat-timeline/tool-renderers/panels/FileMatches.test.ts +114 -0
  85. package/src/client/components/workspace/chat-timeline/tool-renderers/panels/FileMatches.tsx +111 -0
  86. package/src/client/components/workspace/chat-timeline/tool-renderers/panels/Read.tsx +7 -7
  87. package/src/client/components/workspace/chat-timeline/tool-renderers/panels/SearchTool.tsx +9 -59
  88. package/src/client/components/workspace/chat-timeline/tool-renderers/shared/ArtifactBody.tsx +2 -7
  89. package/src/client/components/workspace/chat-timeline/tool-renderers/shared/DiffView.test.ts +27 -28
  90. package/src/client/components/workspace/chat-timeline/tool-renderers/shared/DiffView.tsx +39 -26
  91. package/src/client/components/workspace/chat-timeline/tool-renderers/shared/ExcerptCode.tsx +8 -8
  92. package/src/client/components/workspace/chat-timeline/tool-renderers/shared/HighlightedCode.tsx +35 -0
  93. package/src/client/components/workspace/chat-timeline/tool-renderers/shared/JsonCodeBlock.tsx +4 -4
  94. package/src/client/components/workspace/diff-panel/MergeDiffView.tsx +179 -0
  95. package/src/client/components/workspace/diff-panel/ThemedMergeDiffView.tsx +24 -0
  96. package/src/client/components/workspace/diff-panel/Toolbar.tsx +224 -186
  97. package/src/client/components/workspace/diff-panel/ToolbarSegments.tsx +98 -0
  98. package/src/client/components/workspace/diff-panel/index.tsx +76 -145
  99. package/src/client/components/workspace/diff-panel/merge.ts +315 -0
  100. package/src/client/components/workspace/editor/Body.tsx +4 -7
  101. package/src/client/components/workspace/editor/CommandPalette.tsx +2 -2
  102. package/src/client/components/workspace/editor/FileDocument.tsx +58 -63
  103. package/src/client/components/workspace/editor/FilePane.tsx +4 -7
  104. package/src/client/components/workspace/editor/FindWidget.tsx +7 -2
  105. package/src/client/components/workspace/editor/Toolbar.tsx +220 -123
  106. package/src/client/components/workspace/editor/index.tsx +7 -9
  107. package/src/client/components/workspace/file-explorer/ContextMenu.tsx +2 -1
  108. package/src/client/components/workspace/file-explorer/Modals.tsx +40 -12
  109. package/src/client/components/workspace/file-explorer/OutlineSection.test.tsx +18 -0
  110. package/src/client/components/workspace/file-explorer/OutlineSection.tsx +10 -3
  111. package/src/client/components/workspace/file-explorer/RootMenu.tsx +14 -5
  112. package/src/client/components/workspace/file-explorer/Toolbar.tsx +74 -0
  113. package/src/client/components/workspace/file-explorer/TreeItem.tsx +38 -3
  114. package/src/client/components/workspace/file-explorer/filter.ts +47 -0
  115. package/src/client/components/workspace/file-explorer/index.tsx +77 -64
  116. package/src/client/components/workspace/file-explorer/local-edit.test.ts +135 -0
  117. package/src/client/components/workspace/search-panel/Body.tsx +1 -1
  118. package/src/client/components/workspace/worktree-modal/index.test.tsx +118 -0
  119. package/src/client/components/workspace/worktree-modal/index.tsx +261 -0
  120. package/src/client/hooks/chat/omp/reconnect.test.ts +338 -0
  121. package/src/client/hooks/chat/omp/reconnect.ts +187 -0
  122. package/src/client/hooks/chat/omp/run-liveness.test.ts +71 -0
  123. package/src/client/hooks/chat/omp/run-liveness.ts +65 -0
  124. package/src/client/hooks/chat/omp/session-list.activity.test.ts +114 -0
  125. package/src/client/hooks/chat/omp/session-list.test-util.ts +164 -0
  126. package/src/client/hooks/chat/omp/session-list.test.ts +30 -150
  127. package/src/client/hooks/chat/omp/session-list.tsx +69 -9
  128. package/src/client/hooks/chat/timeline/generating.ts +19 -2
  129. package/src/client/hooks/chat/timeline/index.ts +27 -28
  130. package/src/client/hooks/chat/timeline/lost-run.test.ts +329 -0
  131. package/src/client/hooks/chat/timeline/lost-run.ts +177 -0
  132. package/src/client/hooks/chat/timeline/send-execute.test.ts +2 -0
  133. package/src/client/hooks/chat/timeline/send-steer.test.ts +2 -0
  134. package/src/client/hooks/chat/timeline/send.test.ts +2 -0
  135. package/src/client/hooks/chat/timeline/send.ts +11 -1
  136. package/src/client/hooks/chat/timeline/session-load.test-util.ts +205 -0
  137. package/src/client/hooks/chat/timeline/session-load.test.ts +61 -162
  138. package/src/client/hooks/chat/timeline/session-load.ts +69 -37
  139. package/src/client/hooks/chat/timeline/session-switch.test.ts +65 -0
  140. package/src/client/hooks/chat/timeline/session-switch.ts +63 -0
  141. package/src/client/hooks/chat/timeline/spawn-target.ts +52 -0
  142. package/src/client/hooks/chat/timeline/tool-open.test.ts +74 -0
  143. package/src/client/hooks/chat/timeline/tool-open.ts +52 -8
  144. package/src/client/hooks/code/deferred-highlight.test.ts +182 -0
  145. package/src/client/hooks/code/deferred-highlight.ts +129 -0
  146. package/src/client/hooks/editor/find-state.ts +1 -1
  147. package/src/client/hooks/editor/theme.test.ts +206 -0
  148. package/src/client/hooks/editor/theme.ts +82 -0
  149. package/src/client/hooks/editor/use-editor-drop.test.ts +101 -0
  150. package/src/client/hooks/editor/use-editor-drop.ts +67 -14
  151. package/src/client/hooks/editor/use-editor-find.ts +7 -7
  152. package/src/client/hooks/editor/use-outline-view.test.ts +182 -0
  153. package/src/client/hooks/editor/use-outline-view.ts +94 -7
  154. package/src/client/hooks/editor/use-scroll-restore.test.ts +55 -2
  155. package/src/client/hooks/editor/use-scroll-restore.ts +124 -4
  156. package/src/client/hooks/editor/use-search-reveal.ts +1 -1
  157. package/src/client/hooks/ui/long-press.test.ts +174 -0
  158. package/src/client/hooks/ui/long-press.ts +112 -0
  159. package/src/client/hooks/ui/settings-modal.ts +56 -0
  160. package/src/client/hooks/ui/updates/shell-download.test.ts +75 -0
  161. package/src/client/hooks/ui/updates/shell-download.ts +153 -28
  162. package/src/client/hooks/ui/updates/shell-offer.test.ts +213 -0
  163. package/src/client/hooks/ui/updates/shell-update.test.ts +140 -0
  164. package/src/client/hooks/ui/updates/shell-update.ts +119 -0
  165. package/src/client/hooks/workspace/diff-file.ts +29 -10
  166. package/src/client/hooks/workspace/diff-git-actions.ts +147 -0
  167. package/src/client/hooks/workspace/editor-view.ts +61 -0
  168. package/src/client/hooks/workspace/file-create.ts +41 -11
  169. package/src/client/hooks/workspace/file-listing.ts +56 -1
  170. package/src/client/hooks/workspace/file-tabs.test.ts +62 -5
  171. package/src/client/hooks/workspace/file-tabs.ts +24 -11
  172. package/src/client/hooks/workspace/file-tree-actions.ts +37 -5
  173. package/src/client/hooks/workspace/navbar-session-actions.ts +72 -0
  174. package/src/client/hooks/workspace/worktree/index.ts +165 -0
  175. package/src/client/lib/desktop/bridge.ts +45 -0
  176. package/src/client/lib/search-reveal.ts +1 -1
  177. package/src/client/main.tsx +5 -1
  178. package/src/client/tailwind.css +56 -8
  179. package/src/server/index.ts +7 -2
  180. package/src/server/lib/auth/guard.test.ts +28 -0
  181. package/src/server/lib/auth/guard.ts +10 -0
  182. package/src/server/lib/bundler/titlebar-css.test.ts +42 -1
  183. package/src/server/lib/db/schema.ts +4 -0
  184. package/src/server/lib/db/worktree-registry.server.ts +91 -0
  185. package/src/server/lib/fs/canonical.ts +52 -0
  186. package/src/server/lib/fs/relative-path.ts +48 -0
  187. package/src/server/lib/fs/root-worktree.test.ts +116 -0
  188. package/src/server/lib/fs/root.ts +39 -10
  189. package/src/server/lib/fs/worktree/carry.ts +134 -0
  190. package/src/server/lib/fs/worktree/create.test.ts +249 -0
  191. package/src/server/lib/fs/worktree/create.ts +262 -0
  192. package/src/server/lib/fs/worktree/errors.ts +43 -0
  193. package/src/server/lib/fs/worktree/list.test.ts +207 -0
  194. package/src/server/lib/fs/worktree/list.ts +142 -0
  195. package/src/server/lib/fs/worktree/location.test.ts +206 -0
  196. package/src/server/lib/fs/worktree/location.ts +114 -0
  197. package/src/server/lib/fs/worktree/project-id.ts +53 -0
  198. package/src/server/lib/fs/worktree/remove.test.ts +242 -0
  199. package/src/server/lib/fs/worktree/remove.ts +152 -0
  200. package/src/server/lib/fs/worktree/settings.server.ts +56 -0
  201. package/src/server/lib/fs/worktree/topology.ts +142 -0
  202. package/src/server/lib/lifecycle/claim-port.test.ts +156 -0
  203. package/src/server/lib/lifecycle/port-guard.test.ts +20 -164
  204. package/src/server/lib/lifecycle/port-guard.ts +39 -7
  205. package/src/server/lib/lifecycle/probe-health.test.ts +166 -0
  206. package/src/server/lib/lifecycle/probe.test.ts +77 -164
  207. package/src/server/lib/lifecycle/probe.ts +121 -13
  208. package/src/server/lib/omp/rpc/frame-fold-signals.test.ts +112 -0
  209. package/src/server/lib/omp/rpc/frame-fold.ts +10 -5
  210. package/src/server/lib/omp/session/sidebar-activity.server.test.ts +162 -0
  211. package/src/server/lib/omp/session/sidebar-activity.server.ts +70 -0
  212. package/src/server/lib/omp/session/sidebar-data.canonical.test.ts +155 -0
  213. package/src/server/lib/omp/session/sidebar-data.server.ts +28 -1
  214. package/src/server/lib/omp/session/telemetry/compute.ts +13 -1
  215. package/src/server/lib/omp/session/telemetry.test.ts +33 -0
  216. package/src/server/lib/panels/local-edits.server.ts +33 -0
  217. package/src/server/lib/panels/sync.fixture.test-util.ts +92 -0
  218. package/src/server/lib/panels/sync.local-edits.test.ts +150 -0
  219. package/src/server/lib/panels/sync.server.test.ts +125 -147
  220. package/src/server/lib/panels/sync.server.ts +153 -48
  221. package/src/server/lib/realtime/signals.server.ts +10 -0
  222. package/src/server/lib/realtime/topics/catalog.server.ts +4 -1
  223. package/src/server/lib/realtime/topics.server.ts +16 -0
  224. package/src/server/lib/updates/shell-assets.test.ts +114 -0
  225. package/src/server/lib/updates/shell-assets.ts +200 -0
  226. package/src/server/lib/updates/shell-cache.ts +105 -0
  227. package/src/server/lib/updates/shell-pages.test.ts +187 -0
  228. package/src/server/lib/updates/shell-pages.ts +157 -0
  229. package/src/server/lib/updates/shell-release-desktop.test.ts +166 -0
  230. package/src/server/lib/updates/shell-release.test.ts +59 -71
  231. package/src/server/lib/updates/shell-release.ts +178 -198
  232. package/src/server/routes/fs/action-create.test.ts +18 -13
  233. package/src/server/routes/fs/action-nested.test.ts +184 -0
  234. package/src/server/routes/fs/action.ts +47 -16
  235. package/src/server/routes/fs/git-merge.test.ts +11 -1
  236. package/src/server/routes/fs/read.test.ts +24 -7
  237. package/src/server/routes/fs/scope.test.ts +15 -10
  238. package/src/server/routes/fs/scope.ts +3 -14
  239. package/src/server/routes/index.ts +2 -0
  240. package/src/server/routes/updates/android.ts +6 -1
  241. package/src/server/routes/updates/desktop.ts +59 -0
  242. package/src/server/routes/updates/index.ts +2 -0
  243. package/src/server/routes/updates/ios.ts +5 -1
  244. package/src/server/routes/worktrees/create.ts +138 -0
  245. package/src/server/routes/worktrees/index.ts +25 -0
  246. package/src/server/routes/worktrees/list.ts +134 -0
  247. package/src/server/routes/worktrees/remove.ts +102 -0
  248. package/src/server/routes/worktrees/routes.test.ts +326 -0
  249. package/src/server/routes/worktrees/shared.ts +90 -0
  250. package/src/shared/lib/chat/timeline/omp-callbacks.test.ts +36 -0
  251. package/src/shared/lib/chat/timeline/omp-callbacks.ts +18 -0
  252. package/src/shared/lib/chat/timeline/run-signals.test.ts +2 -0
  253. package/src/shared/lib/code/editor/comment-syntax.test.ts +37 -0
  254. package/src/shared/lib/code/editor/comment-syntax.ts +55 -0
  255. package/src/shared/lib/code/editor/find-replace.test.ts +134 -0
  256. package/src/shared/lib/code/editor/{find.ts → find-replace.ts} +23 -107
  257. package/src/shared/lib/code/editor/{find.test.ts → find-scan.test.ts} +19 -73
  258. package/src/shared/lib/code/editor/find-scan.ts +177 -0
  259. package/src/shared/lib/code/editor/keymap.ts +3 -3
  260. package/src/shared/lib/code/editor/lines.test.ts +7 -55
  261. package/src/shared/lib/code/editor/lines.ts +8 -48
  262. package/src/shared/lib/code/editor/marks.test.ts +4 -5
  263. package/src/shared/lib/code/editor/marks.ts +13 -25
  264. package/src/shared/lib/code/editor/theme-loader.ts +97 -0
  265. package/src/shared/lib/code/editor/themes.generated.ts +156 -0
  266. package/src/shared/lib/code/editor/themes.test.ts +165 -0
  267. package/src/shared/lib/code/editor/themes.ts +165 -0
  268. package/src/shared/lib/code/highlight-memo.test.ts +103 -0
  269. package/src/shared/lib/code/highlight-memo.ts +149 -0
  270. package/src/shared/lib/code/highlighter-warmup.ts +112 -0
  271. package/src/shared/lib/code/highlighter.ts +3 -1
  272. package/src/shared/lib/code/idle.ts +37 -0
  273. package/src/shared/lib/code/outline/rows.test.ts +96 -0
  274. package/src/shared/lib/code/outline/rows.ts +94 -0
  275. package/src/shared/lib/code/syntax-highlight.test.ts +1 -79
  276. package/src/shared/lib/code/syntax-highlight.ts +2 -3
  277. package/src/shared/lib/fs/file-kind-classify.test.ts +25 -11
  278. package/src/shared/lib/fs/file-kind.ts +47 -13
  279. package/src/shared/lib/fs/file-tree.test.ts +183 -0
  280. package/src/shared/lib/fs/file-tree.ts +159 -0
  281. package/src/shared/lib/fs/file-url.test.ts +52 -0
  282. package/src/shared/lib/fs/file-url.ts +37 -0
  283. package/src/shared/lib/fs/patch-sides.test.ts +114 -0
  284. package/src/shared/lib/fs/patch-sides.ts +139 -0
  285. package/src/shared/lib/fs/paths.test.ts +24 -1
  286. package/src/shared/lib/fs/paths.ts +17 -0
  287. package/src/shared/lib/fs/worktree/settings-keys.ts +18 -0
  288. package/src/shared/lib/omp/session/prewarm.ts +7 -0
  289. package/src/shared/lib/realtime/protocol.ts +16 -0
  290. package/src/shared/lib/ui/toolbar-overflow.test.ts +83 -0
  291. package/src/shared/lib/ui/toolbar-overflow.ts +86 -0
  292. package/src/shared/lib/updates/shell-arch.ts +54 -0
  293. package/src/shared/lib/updates/shell-ua.ts +24 -4
  294. package/src/shared/lib/workspace/active-project.ts +23 -0
  295. package/src/shared/lib/workspace/editor-view-mode.test.ts +70 -0
  296. package/src/shared/lib/workspace/editor-view-mode.ts +48 -0
  297. package/src/shared/lib/workspace/panel-widths.test.ts +30 -0
  298. package/src/shared/lib/workspace/panel-widths.ts +25 -5
  299. package/src/shared/lib/workspace/session-state/cache.ts +159 -0
  300. package/src/shared/lib/workspace/session-state/harness.test-util.ts +55 -0
  301. package/src/shared/lib/workspace/session-state/merge.ts +100 -0
  302. package/src/shared/lib/workspace/session-state/store-load.test.ts +206 -0
  303. package/src/shared/lib/workspace/session-state/store.test.ts +17 -139
  304. package/src/shared/lib/workspace/session-state/store.ts +92 -130
  305. package/src/shared/lib/workspace/workspace-modules.test.ts +49 -1
  306. package/src/shared/lib/workspace/workspace-panel-widths.ts +124 -0
  307. package/src/shared/lib/workspace/worktree/branch-name.test.ts +95 -0
  308. package/src/shared/lib/workspace/worktree/branch-name.ts +115 -0
  309. package/src/shared/lib/workspace/worktree/types.ts +104 -0
  310. package/src/shared/types/fs.ts +10 -0
  311. package/src/shared/types/realtime.ts +29 -0
  312. package/src/shared/types/settings/state.ts +10 -0
  313. package/src/shared/types/workspace.ts +14 -0
  314. package/src/test-support/file-explorer-disk.test-util.ts +76 -0
  315. package/src/test-support/file-explorer.test-util.ts +71 -40
  316. package/src/test-support/loopback.ts +183 -0
  317. package/dist/client/static/js/index-nzyjf92m.css +0 -1
  318. package/src/client/components/common/code-editor/handler.test.ts +0 -274
  319. package/src/client/components/common/code-editor/handler.ts +0 -175
  320. package/src/client/components/common/code-editor/index.tsx +0 -314
  321. package/src/client/components/common/code-surface/measure.ts +0 -148
  322. package/src/client/components/workspace/diff-panel/SplitView.tsx +0 -209
  323. package/src/client/components/workspace/diff-panel/UnifiedView.tsx +0 -150
  324. package/src/client/hooks/editor/scroll-container.test.ts +0 -102
  325. package/src/client/hooks/editor/scroll-container.ts +0 -26
  326. package/src/client/hooks/editor/use-code-window.ts +0 -100
  327. package/src/client/hooks/editor/use-editor-history.test.ts +0 -216
  328. package/src/client/hooks/editor/use-editor-history.ts +0 -134
  329. package/src/client/hooks/editor/use-occurrences.test.ts +0 -236
  330. package/src/client/hooks/editor/use-occurrences.ts +0 -98
  331. package/src/shared/lib/code/editor/commands.test.ts +0 -155
  332. package/src/shared/lib/code/editor/commands.ts +0 -260
  333. package/src/shared/lib/code/editor/edits.test.ts +0 -100
  334. package/src/shared/lib/code/editor/edits.ts +0 -122
  335. package/src/shared/lib/code/editor/history.test.ts +0 -118
  336. package/src/shared/lib/code/editor/history.ts +0 -101
  337. package/src/shared/lib/code/editor/layers.test.ts +0 -77
  338. package/src/shared/lib/code/editor/layers.ts +0 -67
  339. package/src/shared/lib/code/editor/line-edits.test.ts +0 -131
  340. package/src/shared/lib/code/editor/line-edits.ts +0 -159
  341. package/src/shared/lib/code/editor/occurrences.test.ts +0 -117
  342. package/src/shared/lib/code/editor/occurrences.ts +0 -111
  343. package/src/shared/lib/code/editor/reset-css.test.ts +0 -35
  344. package/src/shared/lib/code/editor/reset-css.ts +0 -32
  345. package/src/shared/lib/code/editor/text-commands.test.ts +0 -178
  346. package/src/shared/lib/code/editor/text-commands.ts +0 -154
  347. package/src/shared/lib/code/lazy-window.test.ts +0 -161
  348. package/src/shared/lib/code/lazy-window.ts +0 -156
  349. package/src/shared/lib/code/windowed-highlight.ts +0 -114
  350. package/src/shared/lib/fs/diff-parser.test.ts +0 -116
  351. package/src/shared/lib/fs/diff-parser.ts +0 -213
@@ -3,12 +3,12 @@ import { FilePane } from '@/client/components/workspace/editor/FilePane';
3
3
  import type { EditorFindState } from '@/client/hooks/editor/use-editor-find';
4
4
  import type { UseFileEditorResult } from '@/client/hooks/editor/use-file-editor';
5
5
  import type { ResolvedPluginFileView } from '@/client/components/workspace/editor/plugin-file-view';
6
- import type { TextRange } from '@/shared/lib/code/editor/commands';
7
6
  import type { EditorCommand } from '@/shared/lib/code/editor/keymap';
8
7
  import type { CodeSurfaceHandle } from '@/client/components/common/code-surface';
9
8
  import type { RefObject } from 'preact';
10
9
  import type { ViewerKind } from '@/shared/lib/fs/document-kind';
11
10
  import type { OpenedFile } from '@/shared/types/fs';
11
+ import type { EditorThemeState } from '@/client/hooks/editor/theme';
12
12
 
13
13
  interface EditorBodyProps {
14
14
  activeFile: OpenedFile | undefined;
@@ -25,12 +25,11 @@ interface EditorBodyProps {
25
25
  setIsMaximized: (next: boolean) => void;
26
26
  zoomLevel: number;
27
27
  setZoomLevel: (update: (current: number) => number) => void;
28
- occurrences: readonly TextRange[];
29
- setOccurrences: (next: readonly TextRange[]) => void;
30
28
  paletteOpen: boolean;
31
29
  setPaletteOpen: (open: boolean) => void;
32
30
  runCommand: (command: EditorCommand) => void;
33
31
  editorFontFamily: string;
32
+ editorTheme: EditorThemeState;
34
33
  togglePreview: () => void;
35
34
  revealActive: boolean;
36
35
  missing: boolean;
@@ -60,12 +59,11 @@ export function EditorBody({
60
59
  setIsMaximized,
61
60
  zoomLevel,
62
61
  setZoomLevel,
63
- occurrences,
64
- setOccurrences,
65
62
  paletteOpen,
66
63
  setPaletteOpen,
67
64
  runCommand,
68
65
  editorFontFamily,
66
+ editorTheme,
69
67
  togglePreview,
70
68
  revealActive,
71
69
  missing,
@@ -113,12 +111,11 @@ export function EditorBody({
113
111
  setIsMaximized={setIsMaximized}
114
112
  zoomLevel={zoomLevel}
115
113
  setZoomLevel={setZoomLevel}
116
- occurrences={occurrences}
117
- setOccurrences={setOccurrences}
118
114
  paletteOpen={paletteOpen}
119
115
  setPaletteOpen={setPaletteOpen}
120
116
  runCommand={runCommand}
121
117
  editorFontFamily={editorFontFamily}
118
+ editorTheme={editorTheme}
122
119
  togglePreview={togglePreview}
123
120
  revealActive={revealActive}
124
121
  missing={missing}
@@ -7,8 +7,8 @@
7
7
  * The editor's command palette (⌘⇧P).
8
8
  *
9
9
  * Every editor command this app implements is listed here with the chord that
10
- * reaches it, both derived from the same keymap table the textarea matches
11
- * against. The palette is therefore a VIEW of the keymap rather than a second
10
+ * reaches it, both derived from the same keymap table the editor binds against.
11
+ * The palette is therefore a VIEW of the keymap rather than a second
12
12
  * list to keep in sync — a command cannot be listed here and unbound there, and
13
13
  * a chord cannot be shown that does not work.
14
14
  *
@@ -1,3 +1,4 @@
1
+ import { useState } from 'preact/hooks';
1
2
  import type { RefObject } from 'preact';
2
3
  import { MarkdownRenderer } from '@/client/components/common/MarkdownRenderer';
3
4
  import { CodeSurface, type CodeSurfaceHandle } from '@/client/components/common/code-surface';
@@ -8,8 +9,8 @@ import type { UseFileEditorResult } from '@/client/hooks/editor/use-file-editor'
8
9
  import type { EditorFindState } from '@/client/hooks/editor/use-editor-find';
9
10
  import { EDITOR_LINE_HEIGHT } from '@/shared/lib/code/editor/typography';
10
11
  import type { ViewerKind } from '@/shared/lib/fs/document-kind';
11
- import type { TextRange } from '@/shared/lib/code/editor/commands';
12
12
  import type { EditorCommand } from '@/shared/lib/code/editor/keymap';
13
+ import type { EditorThemeState } from '@/client/hooks/editor/theme';
13
14
 
14
15
  interface FileDocumentProps {
15
16
  activeFile: { id: number | string; name: string; path: string; root?: string; repo?: string };
@@ -22,8 +23,7 @@ interface FileDocumentProps {
22
23
  wordWrap: boolean;
23
24
  zoomLevel: number;
24
25
  editorFontFamily: string;
25
- occurrences: readonly TextRange[];
26
- onOccurrencesChange: (next: readonly TextRange[]) => void;
26
+ editorTheme: EditorThemeState;
27
27
  /** The surface this file's kind is drawn by (see `document-kind`). */
28
28
  viewerKind: ViewerKind;
29
29
  /** The rendered view is on for the active file — render it, not the source. */
@@ -57,8 +57,7 @@ export function FileDocument({
57
57
  wordWrap,
58
58
  zoomLevel,
59
59
  editorFontFamily,
60
- occurrences,
61
- onOccurrencesChange,
60
+ editorTheme,
62
61
  viewerKind,
63
62
  isPreview,
64
63
  revealActive,
@@ -67,6 +66,12 @@ export function FileDocument({
67
66
  // SVG picture are drawn by the viewer dispatch instead (they replace the code
68
67
  // surface rather than living inside its scroller).
69
68
  const isMd = viewerKind === 'markdown';
69
+ /**
70
+ * The code surface's scroller, which belongs to CodeMirror and appears only
71
+ * once its view mounts. Reported through `onScroller` because a `ref` cannot
72
+ * reach a node the component does not render.
73
+ */
74
+ const [codeScroller, setCodeScroller] = useState<HTMLElement | null>(null);
70
75
  // The document owns its scroller, so it remembers where the reader left it.
71
76
  // One offset per SURFACE: the rendered markdown and its source are different
72
77
  // documents in the same container and share neither a line nor a height.
@@ -74,26 +79,29 @@ export function FileDocument({
74
79
  tabKey: String(activeFile.id),
75
80
  surface: isMd && isPreview ? 'rendered' : 'code',
76
81
  ready: editor.loaded,
82
+ // `undefined` on the markdown branch, which owns its own scroller and uses
83
+ // the binding's `ref` instead.
84
+ element: isMd && isPreview ? undefined : codeScroller,
77
85
  });
78
86
 
79
87
  return (
80
88
  <div className="relative flex-1 min-h-0 flex flex-col">
81
89
  {find.open ? <FindWidget find={find} /> : null}
82
90
  {paletteOpen ? <CommandPalette onRun={onRunCommand} onClose={onClosePalette} /> : null}
83
- <div
84
- ref={scroll.ref}
85
- onScroll={scroll.onScroll}
86
- // No accessible name exists for a scroll container, so the E2E layer
87
- // addresses it by testid (see `tests/e2e/fixtures/selectors.ts`).
88
- data-testid="editor-scroller"
89
- className="flex-1 overflow-auto bg-paper flex"
90
- >
91
- {isMd && isPreview ? (
92
- // No `prose` wrapper: markdown is styled by `.prose-content` alone
93
- // (the same system the chat timeline uses). The typography plugin
94
- // fought it — `.prose img` added 2em vertical margins that ballooned
95
- // a badge row into its own line box, and `--tw-prose-*` colors
96
- // ignored the theme.
91
+ {isMd && isPreview ? (
92
+ <div
93
+ ref={scroll.ref}
94
+ onScroll={scroll.onScroll}
95
+ // No accessible name exists for a scroll container, so the E2E layer
96
+ // addresses it by testid (see `tests/e2e/fixtures/selectors.ts`).
97
+ data-testid="editor-scroller"
98
+ className="flex-1 overflow-auto bg-paper flex"
99
+ >
100
+ {/* No `prose` wrapper: markdown is styled by `.prose-content` alone
101
+ (the same system the chat timeline uses). The typography plugin
102
+ fought it — `.prose img` added 2em vertical margins that ballooned
103
+ a badge row into its own line box, and `--tw-prose-*` colors
104
+ ignored the theme. */}
97
105
  <div className="p-6 max-w-4xl mx-auto font-sans flex-1" style={{ fontSize: `${zoomLevel}px` }}>
98
106
  <MarkdownRenderer
99
107
  content={editor.content}
@@ -101,50 +109,37 @@ export function FileDocument({
101
109
  scope={{ path: activeFile.path, root: activeFile.root, repo: activeFile.repo }}
102
110
  />
103
111
  </div>
104
- ) : (
105
- <CodeSurface
106
- ref={surfaceRef}
107
- value={editor.content}
108
- onValueChange={editor.onChange}
109
- language={editor.language}
110
- wordWrap={wordWrap}
111
- marks={find.open || revealActive ? find.matches : undefined}
112
- currentMark={find.currentIndex}
113
- occurrences={occurrences}
114
- onOccurrencesChange={onOccurrencesChange}
115
- onCommand={onRunCommand}
116
- rootClassName="flex"
117
- gutterClassName="flex flex-col text-right pl-4 pr-3 select-none text-ink/30 font-mono border-r border-ink/10 bg-canvas sticky left-0 z-10"
118
- gutterStyle={{
119
- fontSize: zoomLevel,
120
- paddingTop: 16,
121
- paddingBottom: 16,
122
- lineHeight: EDITOR_LINE_HEIGHT,
123
- fontFamily: editorFontFamily,
124
- }}
125
- gutterLineClassName="min-w-[1.5rem]"
126
- // `min-w-max` keeps a long line intact and lets the panel scroll
127
- // sideways; while wrapping it would instead widen the column past
128
- // the panel, so the toggle had no effect at all.
129
- editorWrapperClassName={`flex-1 code-surface ${wordWrap ? 'min-w-0' : 'min-w-max'}`}
130
- editorPadding={16}
131
- editorClassName="font-mono focus:outline-none"
132
- editorStyle={{
133
- fontFamily: editorFontFamily,
134
- fontSize: zoomLevel,
135
- lineHeight: EDITOR_LINE_HEIGHT,
136
- minHeight: '100%',
137
- // Breathing room under the last line. It has to live on the
138
- // surface, not on the scroll container: a scroll container's own
139
- // bottom padding is not part of its scrollable overflow, so
140
- // `pb-*` on the scroller left the last line flush with the
141
- // panel's edge (measured: padding-bottom 32px did not change
142
- // scrollHeight by a single pixel).
143
- paddingBottom: 16,
144
- }}
145
- />
146
- )}
147
- </div>
112
+ </div>
113
+ ) : (
114
+ // The code surface owns its own scroller (CodeMirror's), so it is NOT
115
+ // wrapped in one: an outer `overflow-auto` would take the document's
116
+ // height and the editor's viewport would be the whole file.
117
+ <CodeSurface
118
+ ref={surfaceRef}
119
+ value={editor.content}
120
+ onValueChange={editor.onChange}
121
+ language={editor.language}
122
+ wordWrap={wordWrap}
123
+ documentKey={String(activeFile.id)}
124
+ marks={find.open || revealActive ? find.matches : undefined}
125
+ currentMark={find.currentIndex}
126
+ onCommand={onRunCommand}
127
+ onScroller={setCodeScroller}
128
+ scrollTestId="editor-scroller"
129
+ // The editor theme paints its own surface, so the app's `bg-paper`
130
+ // must not sit under it: an explicit theme's background is opaque and
131
+ // would be a rectangle inside the panel's own colour.
132
+ className="flex-1 min-h-0 text-ink select-text"
133
+ themeVars={editorTheme.vars}
134
+ themes={editorTheme.themes}
135
+ padding={16}
136
+ style={{
137
+ fontFamily: editorFontFamily,
138
+ fontSize: `${zoomLevel}px`,
139
+ lineHeight: EDITOR_LINE_HEIGHT,
140
+ }}
141
+ />
142
+ )}
148
143
  </div>
149
144
  );
150
145
  }
@@ -8,11 +8,11 @@ import { ViewerSurface, hasViewerSurface } from '@/client/components/workspace/e
8
8
  import type { CodeSurfaceHandle } from '@/client/components/common/code-surface';
9
9
  import type { UseFileEditorResult } from '@/client/hooks/editor/use-file-editor';
10
10
  import type { EditorFindState } from '@/client/hooks/editor/use-editor-find';
11
- import type { TextRange } from '@/shared/lib/code/editor/commands';
12
11
  import type { EditorCommand } from '@/shared/lib/code/editor/keymap';
13
12
  import { EDITOR_MAX_FONT_SIZE, EDITOR_MIN_FONT_SIZE } from '@/shared/lib/code/editor/typography';
14
13
  import { RENDERED_VIEWERS, type ViewerKind } from '@/shared/lib/fs/document-kind';
15
14
  import type { OpenedFile } from '@/shared/types/fs';
15
+ import type { EditorThemeState } from '@/client/hooks/editor/theme';
16
16
 
17
17
  interface FilePaneProps {
18
18
  activeFile: OpenedFile;
@@ -30,12 +30,11 @@ interface FilePaneProps {
30
30
  setIsMaximized: (next: boolean) => void;
31
31
  zoomLevel: number;
32
32
  setZoomLevel: (update: (current: number) => number) => void;
33
- occurrences: readonly TextRange[];
34
- setOccurrences: (next: readonly TextRange[]) => void;
35
33
  paletteOpen: boolean;
36
34
  setPaletteOpen: (open: boolean) => void;
37
35
  runCommand: (command: EditorCommand) => void;
38
36
  editorFontFamily: string;
37
+ editorTheme: EditorThemeState;
39
38
  togglePreview: () => void;
40
39
  /** A search hit was jumped to in this file, so its matches are painted. */
41
40
  revealActive: boolean;
@@ -72,12 +71,11 @@ export function FilePane({
72
71
  setIsMaximized,
73
72
  zoomLevel,
74
73
  setZoomLevel,
75
- occurrences,
76
- setOccurrences,
77
74
  paletteOpen,
78
75
  setPaletteOpen,
79
76
  runCommand,
80
77
  editorFontFamily,
78
+ editorTheme,
81
79
  togglePreview,
82
80
  revealActive,
83
81
  missing,
@@ -216,8 +214,7 @@ export function FilePane({
216
214
  wordWrap={wordWrap}
217
215
  zoomLevel={zoomLevel}
218
216
  editorFontFamily={editorFontFamily}
219
- occurrences={occurrences}
220
- onOccurrencesChange={setOccurrences}
217
+ editorTheme={editorTheme}
221
218
  isPreview={isPreview}
222
219
  viewerKind={viewerKind}
223
220
  revealActive={revealActive}
@@ -22,7 +22,7 @@ import { EDITOR_KEY_BINDINGS, type EditorCommand } from '@/shared/lib/code/edito
22
22
  import { describeBinding } from '@/shared/lib/ui/key-binding';
23
23
  import { isMacPlatform } from '@/shared/lib/util/platform';
24
24
  import type { EditorFindState } from '@/client/hooks/editor/use-editor-find';
25
- import type { FindOptions } from '@/shared/lib/code/editor/find';
25
+ import type { FindOptions } from '@/shared/lib/code/editor/find-scan';
26
26
 
27
27
  const BUTTON_CLASS =
28
28
  'flex items-center justify-center p-1 rounded transition-colors cursor-pointer disabled:cursor-default disabled:opacity-40';
@@ -112,7 +112,12 @@ export function FindWidget({ find }: FindWidgetProps) {
112
112
  );
113
113
 
114
114
  return (
115
- <div className="absolute top-2 right-4 z-30 flex flex-col gap-1 bg-paper border border-ink/15 rounded-md shadow-lg p-1.5 text-xs text-ink font-sans w-[330px]">
115
+ // `w-[330px]` was wider than the panel's own default (320px), so the bar's
116
+ // leftmost control — Show replace — hung past the panel's edge and its click
117
+ // landed on whatever was beside it. A max width keeps the bar inside the
118
+ // panel it belongs to at any width, and `min-w-0` lets the fields shrink
119
+ // with it instead of pushing the buttons out.
120
+ <div className="absolute top-2 right-2 z-30 flex w-[330px] max-w-[calc(100%-1rem)] min-w-0 flex-col gap-1 bg-paper border border-ink/15 rounded-md shadow-lg p-1.5 text-xs text-ink font-sans">
116
121
  <div className="flex items-center gap-1">
117
122
  <button
118
123
  type="button"