@cerbur/clutch-dsh-worktree 0.1.16 → 0.1.18

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 (429) hide show
  1. package/README.md +314 -43
  2. package/README.zh.md +263 -37
  3. package/assets/screenshots/screenshots-dashboard.png +0 -0
  4. package/assets/screenshots/screenshots-en.png +0 -0
  5. package/assets/screenshots/screenshots-git-reviewer.png +0 -0
  6. package/assets/screenshots/screenshots-import.png +0 -0
  7. package/assets/screenshots/screenshots-worktree-tool.png +0 -0
  8. package/assets/screenshots/screenshots-zh.png +0 -0
  9. package/cordis.patch.yml +6 -19
  10. package/lib/client/WorktreeSurface.d.ts.map +1 -1
  11. package/lib/client/WorktreeSurface.js +41 -13
  12. package/lib/client/WorktreeSurface.js.map +1 -1
  13. package/lib/client/branch/GitBranchSelector.d.ts +23 -0
  14. package/lib/client/branch/GitBranchSelector.d.ts.map +1 -0
  15. package/lib/client/branch/GitBranchSelector.js +142 -0
  16. package/lib/client/branch/GitBranchSelector.js.map +1 -0
  17. package/lib/client/command-activity.d.ts +11 -0
  18. package/lib/client/command-activity.d.ts.map +1 -0
  19. package/lib/client/command-activity.js +71 -0
  20. package/lib/client/command-activity.js.map +1 -0
  21. package/lib/client/context/worktree-context-store.d.ts.map +1 -1
  22. package/lib/client/context/worktree-context-store.js +1 -0
  23. package/lib/client/context/worktree-context-store.js.map +1 -1
  24. package/lib/client/context/worktree-context.d.ts +3 -2
  25. package/lib/client/context/worktree-context.d.ts.map +1 -1
  26. package/lib/client/context/worktree-context.js +5 -3
  27. package/lib/client/context/worktree-context.js.map +1 -1
  28. package/lib/client/dashboard/DashboardRequest.d.ts +2 -1
  29. package/lib/client/dashboard/DashboardRequest.d.ts.map +1 -1
  30. package/lib/client/dashboard/DashboardRequest.js +3 -3
  31. package/lib/client/dashboard/DashboardRequest.js.map +1 -1
  32. package/lib/client/dashboard/WorktreeDashboard.d.ts +6 -2
  33. package/lib/client/dashboard/WorktreeDashboard.d.ts.map +1 -1
  34. package/lib/client/dashboard/WorktreeDashboard.js +111 -89
  35. package/lib/client/dashboard/WorktreeDashboard.js.map +1 -1
  36. package/lib/client/dashboard/WorktreeInstructions.d.ts +2 -1
  37. package/lib/client/dashboard/WorktreeInstructions.d.ts.map +1 -1
  38. package/lib/client/dashboard/WorktreeInstructions.js +27 -8
  39. package/lib/client/dashboard/WorktreeInstructions.js.map +1 -1
  40. package/lib/client/dashboard/dashboard-overlay.d.ts.map +1 -1
  41. package/lib/client/dashboard/dashboard-overlay.js +38 -52
  42. package/lib/client/dashboard/dashboard-overlay.js.map +1 -1
  43. package/lib/client/dashboard/dashboard-selection.d.ts +4 -2
  44. package/lib/client/dashboard/dashboard-selection.d.ts.map +1 -1
  45. package/lib/client/dashboard/dashboard-selection.js +6 -4
  46. package/lib/client/dashboard/dashboard-selection.js.map +1 -1
  47. package/lib/client/dashboard/git/GitChangedFiles.d.ts +2 -1
  48. package/lib/client/dashboard/git/GitChangedFiles.d.ts.map +1 -1
  49. package/lib/client/dashboard/git/GitChangedFiles.js +8 -6
  50. package/lib/client/dashboard/git/GitChangedFiles.js.map +1 -1
  51. package/lib/client/dashboard/git/GitCommitList.d.ts +6 -1
  52. package/lib/client/dashboard/git/GitCommitList.d.ts.map +1 -1
  53. package/lib/client/dashboard/git/GitCommitList.js +34 -29
  54. package/lib/client/dashboard/git/GitCommitList.js.map +1 -1
  55. package/lib/client/dashboard/git/GitCommitStats.d.ts +8 -0
  56. package/lib/client/dashboard/git/GitCommitStats.d.ts.map +1 -0
  57. package/lib/client/dashboard/git/GitCommitStats.js +7 -0
  58. package/lib/client/dashboard/git/GitCommitStats.js.map +1 -0
  59. package/lib/client/dashboard/git/WorktreeGitOverview.d.ts.map +1 -1
  60. package/lib/client/dashboard/git/WorktreeGitOverview.js +2 -1
  61. package/lib/client/dashboard/git/WorktreeGitOverview.js.map +1 -1
  62. package/lib/client/dashboard/git/WorktreeGitPanel.d.ts +3 -2
  63. package/lib/client/dashboard/git/WorktreeGitPanel.d.ts.map +1 -1
  64. package/lib/client/dashboard/git/WorktreeGitPanel.js +79 -14
  65. package/lib/client/dashboard/git/WorktreeGitPanel.js.map +1 -1
  66. package/lib/client/dashboard/git/file-address.d.ts +5 -1
  67. package/lib/client/dashboard/git/file-address.d.ts.map +1 -1
  68. package/lib/client/dashboard/git/file-address.js +49 -11
  69. package/lib/client/dashboard/git/file-address.js.map +1 -1
  70. package/lib/client/dashboard/git/git-facts.js +1 -1
  71. package/lib/client/dashboard/git/git-facts.js.map +1 -1
  72. package/lib/client/dashboard/git/useWorktreeGitState.d.ts +7 -2
  73. package/lib/client/dashboard/git/useWorktreeGitState.d.ts.map +1 -1
  74. package/lib/client/dashboard/git/useWorktreeGitState.js +88 -22
  75. package/lib/client/dashboard/git/useWorktreeGitState.js.map +1 -1
  76. package/lib/client/dsh-icons.d.ts +4 -0
  77. package/lib/client/dsh-icons.d.ts.map +1 -1
  78. package/lib/client/dsh-icons.js +5 -1
  79. package/lib/client/dsh-icons.js.map +1 -1
  80. package/lib/client/dsh-slot-contract.d.ts +9 -1
  81. package/lib/client/dsh-slot-contract.d.ts.map +1 -1
  82. package/lib/client/entry.d.ts.map +1 -1
  83. package/lib/client/entry.js +39 -2
  84. package/lib/client/entry.js.map +1 -1
  85. package/lib/client/layout/app-frame.d.ts +12 -0
  86. package/lib/client/layout/app-frame.d.ts.map +1 -0
  87. package/lib/client/layout/app-frame.js +82 -0
  88. package/lib/client/layout/app-frame.js.map +1 -0
  89. package/lib/client/locales.d.ts +184 -2
  90. package/lib/client/locales.d.ts.map +1 -1
  91. package/lib/client/locales.js +250 -68
  92. package/lib/client/locales.js.map +1 -1
  93. package/lib/client/overlay/overlay-bounds.d.ts.map +1 -1
  94. package/lib/client/overlay/overlay-bounds.js +8 -3
  95. package/lib/client/overlay/overlay-bounds.js.map +1 -1
  96. package/lib/client/overlay/sidebar-overlay-geometry.d.ts +3 -1
  97. package/lib/client/overlay/sidebar-overlay-geometry.d.ts.map +1 -1
  98. package/lib/client/overlay/sidebar-overlay-geometry.js +94 -34
  99. package/lib/client/overlay/sidebar-overlay-geometry.js.map +1 -1
  100. package/lib/client/restart-notice.d.ts +10 -3
  101. package/lib/client/restart-notice.d.ts.map +1 -1
  102. package/lib/client/restart-notice.js +44 -11
  103. package/lib/client/restart-notice.js.map +1 -1
  104. package/lib/client/select/SearchableSingleSelect.d.ts +44 -0
  105. package/lib/client/select/SearchableSingleSelect.d.ts.map +1 -0
  106. package/lib/client/select/SearchableSingleSelect.js +180 -0
  107. package/lib/client/select/SearchableSingleSelect.js.map +1 -0
  108. package/lib/client/select/WorktreeSelector.d.ts +14 -0
  109. package/lib/client/select/WorktreeSelector.d.ts.map +1 -0
  110. package/lib/client/select/WorktreeSelector.js +11 -0
  111. package/lib/client/select/WorktreeSelector.js.map +1 -0
  112. package/lib/client/session/session-view.d.ts +16 -2
  113. package/lib/client/session/session-view.d.ts.map +1 -1
  114. package/lib/client/session/session-view.js +24 -10
  115. package/lib/client/session/session-view.js.map +1 -1
  116. package/lib/client/session/worktree-session.d.ts +1 -0
  117. package/lib/client/session/worktree-session.d.ts.map +1 -1
  118. package/lib/client/session/worktree-session.js +3 -1
  119. package/lib/client/session/worktree-session.js.map +1 -1
  120. package/lib/client/settings/ToolSettings.d.ts +9 -0
  121. package/lib/client/settings/ToolSettings.d.ts.map +1 -0
  122. package/lib/client/settings/ToolSettings.js +77 -0
  123. package/lib/client/settings/ToolSettings.js.map +1 -0
  124. package/lib/client/settings/WorktreeSettings.d.ts +8 -0
  125. package/lib/client/settings/WorktreeSettings.d.ts.map +1 -0
  126. package/lib/client/settings/WorktreeSettings.js +46 -0
  127. package/lib/client/settings/WorktreeSettings.js.map +1 -0
  128. package/lib/client/settings/WorktreeSettingsNavIcon.d.ts +6 -0
  129. package/lib/client/settings/WorktreeSettingsNavIcon.d.ts.map +1 -0
  130. package/lib/client/settings/WorktreeSettingsNavIcon.js +51 -0
  131. package/lib/client/settings/WorktreeSettingsNavIcon.js.map +1 -0
  132. package/lib/client/settings/diagnostics.d.ts +24 -0
  133. package/lib/client/settings/diagnostics.d.ts.map +1 -0
  134. package/lib/client/settings/diagnostics.js +63 -0
  135. package/lib/client/settings/diagnostics.js.map +1 -0
  136. package/lib/client/settings/settings-navigation.d.ts +7 -0
  137. package/lib/client/settings/settings-navigation.d.ts.map +1 -0
  138. package/lib/client/settings/settings-navigation.js +12 -0
  139. package/lib/client/settings/settings-navigation.js.map +1 -0
  140. package/lib/client/surface/actions/useLifecycleActions.d.ts +2 -1
  141. package/lib/client/surface/actions/useLifecycleActions.d.ts.map +1 -1
  142. package/lib/client/surface/actions/useLifecycleActions.js +15 -6
  143. package/lib/client/surface/actions/useLifecycleActions.js.map +1 -1
  144. package/lib/client/surface/actions/useSessionActions.d.ts.map +1 -1
  145. package/lib/client/surface/actions/useSessionActions.js +6 -6
  146. package/lib/client/surface/actions/useSessionActions.js.map +1 -1
  147. package/lib/client/surface/actions/useWorktreeRegistration.d.ts +1 -1
  148. package/lib/client/surface/actions/useWorktreeRegistration.d.ts.map +1 -1
  149. package/lib/client/surface/actions/useWorktreeRegistration.js +36 -13
  150. package/lib/client/surface/actions/useWorktreeRegistration.js.map +1 -1
  151. package/lib/client/surface/components/NotificationToasts.d.ts +19 -3
  152. package/lib/client/surface/components/NotificationToasts.d.ts.map +1 -1
  153. package/lib/client/surface/components/NotificationToasts.js +73 -7
  154. package/lib/client/surface/components/NotificationToasts.js.map +1 -1
  155. package/lib/client/surface/components/OverlayScrollbar.d.ts +6 -0
  156. package/lib/client/surface/components/OverlayScrollbar.d.ts.map +1 -0
  157. package/lib/client/surface/components/OverlayScrollbar.js +84 -0
  158. package/lib/client/surface/components/OverlayScrollbar.js.map +1 -0
  159. package/lib/client/surface/components/RegistrationDialog.d.ts +3 -3
  160. package/lib/client/surface/components/RegistrationDialog.d.ts.map +1 -1
  161. package/lib/client/surface/components/RegistrationDialog.js +70 -5
  162. package/lib/client/surface/components/RegistrationDialog.js.map +1 -1
  163. package/lib/client/surface/components/RestartToast.d.ts.map +1 -1
  164. package/lib/client/surface/components/RestartToast.js +4 -3
  165. package/lib/client/surface/components/RestartToast.js.map +1 -1
  166. package/lib/client/surface/components/SurfaceContent.d.ts.map +1 -1
  167. package/lib/client/surface/components/SurfaceContent.js +110 -39
  168. package/lib/client/surface/components/SurfaceContent.js.map +1 -1
  169. package/lib/client/surface/components/WorkspaceTree.d.ts.map +1 -1
  170. package/lib/client/surface/components/WorkspaceTree.js +13 -9
  171. package/lib/client/surface/components/WorkspaceTree.js.map +1 -1
  172. package/lib/client/surface/components/dialogs.d.ts +1 -1
  173. package/lib/client/surface/components/dialogs.d.ts.map +1 -1
  174. package/lib/client/surface/components/dialogs.js +34 -21
  175. package/lib/client/surface/components/dialogs.js.map +1 -1
  176. package/lib/client/surface/components/rows.d.ts +1 -1
  177. package/lib/client/surface/components/rows.d.ts.map +1 -1
  178. package/lib/client/surface/components/rows.js +15 -97
  179. package/lib/client/surface/components/rows.js.map +1 -1
  180. package/lib/client/surface/notification-queue.d.ts +15 -0
  181. package/lib/client/surface/notification-queue.d.ts.map +1 -1
  182. package/lib/client/surface/notification-queue.js +13 -2
  183. package/lib/client/surface/notification-queue.js.map +1 -1
  184. package/lib/client/surface/state/useRegistrationState.d.ts +6 -1
  185. package/lib/client/surface/state/useRegistrationState.d.ts.map +1 -1
  186. package/lib/client/surface/state/useRegistrationState.js +7 -0
  187. package/lib/client/surface/state/useRegistrationState.js.map +1 -1
  188. package/lib/client/surface/state/useSurfaceRefresh.d.ts +1 -1
  189. package/lib/client/surface/state/useSurfaceRefresh.d.ts.map +1 -1
  190. package/lib/client/surface/state/useSurfaceRefresh.js +13 -1
  191. package/lib/client/surface/state/useSurfaceRefresh.js.map +1 -1
  192. package/lib/client/surface/state/useSurfaceSources.d.ts +1 -1
  193. package/lib/client/surface/state/useSurfaceSources.d.ts.map +1 -1
  194. package/lib/client/surface/state/useSurfaceSources.js +4 -2
  195. package/lib/client/surface/state/useSurfaceSources.js.map +1 -1
  196. package/lib/client/surface/state/useTitleMarquee.d.ts +7 -0
  197. package/lib/client/surface/state/useTitleMarquee.d.ts.map +1 -0
  198. package/lib/client/surface/state/useTitleMarquee.js +60 -0
  199. package/lib/client/surface/state/useTitleMarquee.js.map +1 -0
  200. package/lib/client/surface/types.d.ts +12 -1
  201. package/lib/client/surface/types.d.ts.map +1 -1
  202. package/lib/client/view/worktree-error-copy.d.ts.map +1 -1
  203. package/lib/client/view/worktree-error-copy.js +73 -14
  204. package/lib/client/view/worktree-error-copy.js.map +1 -1
  205. package/lib/client/view/worktree-view-errors.d.ts.map +1 -1
  206. package/lib/client/view/worktree-view-errors.js +13 -5
  207. package/lib/client/view/worktree-view-errors.js.map +1 -1
  208. package/lib/client/view/worktree-view-read.d.ts +4 -2
  209. package/lib/client/view/worktree-view-read.d.ts.map +1 -1
  210. package/lib/client/view/worktree-view-read.js +34 -17
  211. package/lib/client/view/worktree-view-read.js.map +1 -1
  212. package/lib/client/worktree-connection.d.ts +9 -2
  213. package/lib/client/worktree-connection.d.ts.map +1 -1
  214. package/lib/client/worktree-connection.js +24 -1
  215. package/lib/client/worktree-connection.js.map +1 -1
  216. package/lib/client/worktree-tool-changes.d.ts +13 -0
  217. package/lib/client/worktree-tool-changes.d.ts.map +1 -0
  218. package/lib/client/worktree-tool-changes.js +64 -0
  219. package/lib/client/worktree-tool-changes.js.map +1 -0
  220. package/lib/client.js +3503 -1310
  221. package/lib/client.js.map +1 -1
  222. package/lib/contract/index.contract.js +15 -0
  223. package/lib/contract/index.contract.js.map +1 -1
  224. package/lib/contract/index.d.ts +79 -12
  225. package/lib/contract/index.d.ts.map +1 -1
  226. package/lib/contract/index.js +12 -0
  227. package/lib/contract/index.js.map +1 -1
  228. package/lib/contract/tool-settings.d.ts +28 -0
  229. package/lib/contract/tool-settings.d.ts.map +1 -0
  230. package/lib/contract/tool-settings.js +10 -0
  231. package/lib/contract/tool-settings.js.map +1 -0
  232. package/lib/contract/worktree-tool-changes.d.ts +10 -0
  233. package/lib/contract/worktree-tool-changes.d.ts.map +1 -0
  234. package/lib/contract/worktree-tool-changes.js +2 -0
  235. package/lib/contract/worktree-tool-changes.js.map +1 -0
  236. package/lib/host/permission-preset-append.d.ts +15 -0
  237. package/lib/host/permission-preset-append.d.ts.map +1 -0
  238. package/lib/host/permission-preset-append.js +63 -0
  239. package/lib/host/permission-preset-append.js.map +1 -0
  240. package/lib/host/remote.d.ts.map +1 -1
  241. package/lib/host/remote.js +7 -0
  242. package/lib/host/remote.js.map +1 -1
  243. package/lib/host/service.d.ts +30 -6
  244. package/lib/host/service.d.ts.map +1 -1
  245. package/lib/host/service.js +85 -11
  246. package/lib/host/service.js.map +1 -1
  247. package/lib/host/tool-settings.d.ts +14 -0
  248. package/lib/host/tool-settings.d.ts.map +1 -0
  249. package/lib/host/tool-settings.js +98 -0
  250. package/lib/host/tool-settings.js.map +1 -0
  251. package/lib/host/worktree-permission-manager.d.ts.map +1 -1
  252. package/lib/host/worktree-permission-manager.js +2 -4
  253. package/lib/host/worktree-permission-manager.js.map +1 -1
  254. package/lib/host/worktree-tool-changes.d.ts +12 -0
  255. package/lib/host/worktree-tool-changes.d.ts.map +1 -0
  256. package/lib/host/worktree-tool-changes.js +60 -0
  257. package/lib/host/worktree-tool-changes.js.map +1 -0
  258. package/lib/manage/manager-git-history.d.ts +5 -7
  259. package/lib/manage/manager-git-history.d.ts.map +1 -1
  260. package/lib/manage/manager-git-history.js +185 -91
  261. package/lib/manage/manager-git-history.js.map +1 -1
  262. package/lib/manage/manager-git-paths.d.ts +7 -0
  263. package/lib/manage/manager-git-paths.d.ts.map +1 -0
  264. package/lib/manage/manager-git-paths.js +62 -0
  265. package/lib/manage/manager-git-paths.js.map +1 -0
  266. package/lib/manage/manager-sessions.d.ts +5 -0
  267. package/lib/manage/manager-sessions.d.ts.map +1 -1
  268. package/lib/manage/manager-sessions.js +34 -11
  269. package/lib/manage/manager-sessions.js.map +1 -1
  270. package/lib/manage/manager-support.d.ts +3 -1
  271. package/lib/manage/manager-support.d.ts.map +1 -1
  272. package/lib/manage/manager-support.js +17 -0
  273. package/lib/manage/manager-support.js.map +1 -1
  274. package/lib/manage/manager-worktree-lifecycle.d.ts.map +1 -1
  275. package/lib/manage/manager-worktree-lifecycle.js +5 -4
  276. package/lib/manage/manager-worktree-lifecycle.js.map +1 -1
  277. package/lib/manage/manager-worktrees.d.ts +10 -1
  278. package/lib/manage/manager-worktrees.d.ts.map +1 -1
  279. package/lib/manage/manager-worktrees.js +141 -34
  280. package/lib/manage/manager-worktrees.js.map +1 -1
  281. package/lib/manage/manager.d.ts +22 -5
  282. package/lib/manage/manager.d.ts.map +1 -1
  283. package/lib/manage/manager.js +76 -4
  284. package/lib/manage/manager.js.map +1 -1
  285. package/lib/manage/types.d.ts +10 -1
  286. package/lib/manage/types.d.ts.map +1 -1
  287. package/lib/provider/generated-name.d.ts.map +1 -1
  288. package/lib/provider/generated-name.js +5 -4
  289. package/lib/provider/generated-name.js.map +1 -1
  290. package/lib/provider/git/adapter.d.ts +13 -12
  291. package/lib/provider/git/adapter.d.ts.map +1 -1
  292. package/lib/provider/git/adapter.js +157 -31
  293. package/lib/provider/git/adapter.js.map +1 -1
  294. package/lib/provider/git/branch-name.d.ts +5 -0
  295. package/lib/provider/git/branch-name.d.ts.map +1 -0
  296. package/lib/provider/git/branch-name.js +16 -0
  297. package/lib/provider/git/branch-name.js.map +1 -0
  298. package/lib/provider/git/branches.d.ts +11 -0
  299. package/lib/provider/git/branches.d.ts.map +1 -0
  300. package/lib/provider/git/branches.js +37 -0
  301. package/lib/provider/git/branches.js.map +1 -0
  302. package/lib/provider/mutation-token.d.ts +1 -1
  303. package/lib/provider/mutation-token.d.ts.map +1 -1
  304. package/lib/provider/mutation-token.js +1 -0
  305. package/lib/provider/mutation-token.js.map +1 -1
  306. package/lib/provider/sidecar/repository.d.ts.map +1 -1
  307. package/lib/provider/sidecar/repository.js +3 -1
  308. package/lib/provider/sidecar/repository.js.map +1 -1
  309. package/lib/provider/sidecar/sidecar-schema.d.ts.map +1 -1
  310. package/lib/provider/sidecar/sidecar-schema.js +26 -4
  311. package/lib/provider/sidecar/sidecar-schema.js.map +1 -1
  312. package/lib/provider/transaction/operations/adopt-branch.d.ts.map +1 -1
  313. package/lib/provider/transaction/operations/adopt-branch.js +6 -5
  314. package/lib/provider/transaction/operations/adopt-branch.js.map +1 -1
  315. package/lib/provider/transaction/operations/clean.d.ts.map +1 -1
  316. package/lib/provider/transaction/operations/clean.js +20 -19
  317. package/lib/provider/transaction/operations/clean.js.map +1 -1
  318. package/lib/provider/transaction/operations/create.d.ts +1 -1
  319. package/lib/provider/transaction/operations/create.d.ts.map +1 -1
  320. package/lib/provider/transaction/operations/create.js +39 -17
  321. package/lib/provider/transaction/operations/create.js.map +1 -1
  322. package/lib/provider/transaction/operations/import.d.ts.map +1 -1
  323. package/lib/provider/transaction/operations/import.js +7 -1
  324. package/lib/provider/transaction/operations/import.js.map +1 -1
  325. package/lib/provider/transaction/operations/remove.d.ts.map +1 -1
  326. package/lib/provider/transaction/operations/remove.js +20 -19
  327. package/lib/provider/transaction/operations/remove.js.map +1 -1
  328. package/lib/provider/transaction/recovery/failure-recovery.d.ts.map +1 -1
  329. package/lib/provider/transaction/recovery/failure-recovery.js +22 -20
  330. package/lib/provider/transaction/recovery/failure-recovery.js.map +1 -1
  331. package/lib/provider/transaction/recovery/recover.d.ts.map +1 -1
  332. package/lib/provider/transaction/recovery/recover.js +11 -4
  333. package/lib/provider/transaction/recovery/recover.js.map +1 -1
  334. package/lib/provider/transaction/support/inspection.d.ts.map +1 -1
  335. package/lib/provider/transaction/support/inspection.js +3 -2
  336. package/lib/provider/transaction/support/inspection.js.map +1 -1
  337. package/lib/provider/transaction/support/journal.d.ts.map +1 -1
  338. package/lib/provider/transaction/support/journal.js +9 -5
  339. package/lib/provider/transaction/support/journal.js.map +1 -1
  340. package/lib/provider/transaction/support/path-safety.d.ts.map +1 -1
  341. package/lib/provider/transaction/support/path-safety.js +4 -3
  342. package/lib/provider/transaction/support/path-safety.js.map +1 -1
  343. package/lib/provider/transaction/types.d.ts +2 -1
  344. package/lib/provider/transaction/types.d.ts.map +1 -1
  345. package/lib/provider/types.d.ts +27 -5
  346. package/lib/provider/types.d.ts.map +1 -1
  347. package/lib/provider/types.js +1 -1
  348. package/lib/provider/types.js.map +1 -1
  349. package/lib/provider/worktree-path.d.ts +10 -0
  350. package/lib/provider/worktree-path.d.ts.map +1 -0
  351. package/lib/provider/worktree-path.js +47 -0
  352. package/lib/provider/worktree-path.js.map +1 -0
  353. package/lib/tool/context.d.ts +14 -0
  354. package/lib/tool/context.d.ts.map +1 -0
  355. package/lib/tool/context.js +95 -0
  356. package/lib/tool/context.js.map +1 -0
  357. package/lib/tool/delegation.d.ts +41 -0
  358. package/lib/tool/delegation.d.ts.map +1 -0
  359. package/lib/tool/delegation.js +196 -0
  360. package/lib/tool/delegation.js.map +1 -0
  361. package/lib/tool/errors.d.ts +3 -0
  362. package/lib/tool/errors.d.ts.map +1 -0
  363. package/lib/tool/errors.js +63 -0
  364. package/lib/tool/errors.js.map +1 -0
  365. package/lib/tool/guidance.d.ts +5 -0
  366. package/lib/tool/guidance.d.ts.map +1 -0
  367. package/lib/tool/guidance.js +48 -0
  368. package/lib/tool/guidance.js.map +1 -0
  369. package/lib/tool/history.d.ts +27 -0
  370. package/lib/tool/history.d.ts.map +1 -0
  371. package/lib/tool/history.js +157 -0
  372. package/lib/tool/history.js.map +1 -0
  373. package/lib/tool/index.d.ts +8 -0
  374. package/lib/tool/index.d.ts.map +1 -0
  375. package/lib/tool/index.js +296 -0
  376. package/lib/tool/index.js.map +1 -0
  377. package/lib/tool/inputs.d.ts +12 -0
  378. package/lib/tool/inputs.d.ts.map +1 -0
  379. package/lib/tool/inputs.js +24 -0
  380. package/lib/tool/inputs.js.map +1 -0
  381. package/lib/tool/list-models.d.ts +3 -0
  382. package/lib/tool/list-models.d.ts.map +1 -0
  383. package/lib/tool/list-models.js +38 -0
  384. package/lib/tool/list-models.js.map +1 -0
  385. package/lib/tool/list-sessions.d.ts +3 -0
  386. package/lib/tool/list-sessions.d.ts.map +1 -0
  387. package/lib/tool/list-sessions.js +70 -0
  388. package/lib/tool/list-sessions.js.map +1 -0
  389. package/lib/tool/list-worktrees.d.ts +3 -0
  390. package/lib/tool/list-worktrees.d.ts.map +1 -0
  391. package/lib/tool/list-worktrees.js +46 -0
  392. package/lib/tool/list-worktrees.js.map +1 -0
  393. package/lib/tool/native-session.d.ts +74 -0
  394. package/lib/tool/native-session.d.ts.map +1 -0
  395. package/lib/tool/native-session.js +248 -0
  396. package/lib/tool/native-session.js.map +1 -0
  397. package/lib/tool/new-worktree.d.ts +3 -0
  398. package/lib/tool/new-worktree.d.ts.map +1 -0
  399. package/lib/tool/new-worktree.js +81 -0
  400. package/lib/tool/new-worktree.js.map +1 -0
  401. package/lib/tool/outputs.d.ts +50 -0
  402. package/lib/tool/outputs.d.ts.map +1 -0
  403. package/lib/tool/outputs.js +65 -0
  404. package/lib/tool/outputs.js.map +1 -0
  405. package/lib/tool/report-result.d.ts +3 -0
  406. package/lib/tool/report-result.d.ts.map +1 -0
  407. package/lib/tool/report-result.js +83 -0
  408. package/lib/tool/report-result.js.map +1 -0
  409. package/lib/tool/schema.d.ts +7 -0
  410. package/lib/tool/schema.d.ts.map +1 -0
  411. package/lib/tool/schema.js +92 -0
  412. package/lib/tool/schema.js.map +1 -0
  413. package/lib/tool/send-message.d.ts +3 -0
  414. package/lib/tool/send-message.d.ts.map +1 -0
  415. package/lib/tool/send-message.js +64 -0
  416. package/lib/tool/send-message.js.map +1 -0
  417. package/lib/tool/span-worktree.d.ts +3 -0
  418. package/lib/tool/span-worktree.d.ts.map +1 -0
  419. package/lib/tool/span-worktree.js +114 -0
  420. package/lib/tool/span-worktree.js.map +1 -0
  421. package/lib/tool/types.d.ts +54 -0
  422. package/lib/tool/types.d.ts.map +1 -0
  423. package/lib/tool/types.js +2 -0
  424. package/lib/tool/types.js.map +1 -0
  425. package/lib/typert.host.js +387 -46
  426. package/lib/typert.remote-client.d.ts +17 -5
  427. package/lib/typert.remote-client.d.ts.map +1 -1
  428. package/lib/typert.remote-client.js +387 -46
  429. package/package.json +17 -3
@@ -1,6 +1,11 @@
1
+ import { isSafeBranchIdentity } from '../provider/git/branch-name.js';
2
+ import { readBranchFacts, findBranchIdentity, canonicalBranchIdentity } from '../provider/git/branches.js';
3
+ import { gitWorktreeRoot } from '../contract/index.js';
1
4
  import { WORKTREE_GIT_COMMIT_PATTERN, WORKTREE_GIT_SUMMARY, WORKTREE_GIT_WORKING_TREE, } from '../contract/index.js';
2
5
  import { providerError } from '../provider/types.js';
3
6
  import { isDirectory, requireWorkspace, samePhysicalPath } from './manager-support.js';
7
+ import { projectWorktreePath } from '../provider/worktree-path.js';
8
+ import { workspaceGitPaths } from './manager-git-paths.js';
4
9
  /** Shared with Contract/Provider/Client so commit-SHA validation cannot drift. */
5
10
  const COMMIT_PATTERN = WORKTREE_GIT_COMMIT_PATTERN;
6
11
  /**
@@ -56,14 +61,32 @@ async function findLiveWorktree(worktrees, absolutePath) {
56
61
  }
57
62
  return undefined;
58
63
  }
59
- async function resolveWorktree(context, input) {
64
+ async function resolveWorktree(context, input, compareMain = true) {
60
65
  const workspace = await requireWorkspace(context, input.workspaceId);
61
66
  if (isMainWorktreeId(input.worktreeId, input.workspaceId)) {
62
67
  // The imported Workspace can be nested, while committed Git paths are root-relative.
63
68
  const repositoryRoot = context.git.resolveRepositoryRoot
64
69
  ? await context.git.resolveRepositoryRoot(workspace.rootPath, { signal: context.signal })
65
70
  : workspace.rootPath;
66
- return { main: true, workspaceRoot: workspace.rootPath, repositoryRoot };
71
+ if (compareMain && input.baseBranch !== undefined) {
72
+ // A request-local checkout context reuses comparison and path authorization.
73
+ // It is never read from or written to the sidecar.
74
+ const headCommit = await gitRead(context, 'resolveCommit', input.worktreeId)(repositoryRoot, 'HEAD', { signal: context.signal });
75
+ return { main: false, value: {
76
+ workspaceRoot: workspace.rootPath,
77
+ repositoryRoot,
78
+ record: {
79
+ workspaceId: input.workspaceId, worktreeId: input.worktreeId,
80
+ absolutePath: workspace.rootPath, gitRootPath: repositoryRoot,
81
+ branch: 'HEAD', source: 'external', status: 'active',
82
+ },
83
+ live: { absolutePath: repositoryRoot, headCommit },
84
+ } };
85
+ }
86
+ const headCommit = compareMain && context.git.resolveCommit
87
+ ? await context.git.resolveCommit(repositoryRoot, 'HEAD', { signal: context.signal })
88
+ : undefined;
89
+ return { main: true, workspaceRoot: workspace.rootPath, repositoryRoot, headCommit };
67
90
  }
68
91
  const snapshot = await context.sidecar.read(input.workspaceId);
69
92
  if (snapshot.pendingOperation !== undefined || (snapshot.recoveryIssues?.length ?? 0) > 0) {
@@ -85,22 +108,22 @@ async function resolveWorktree(context, input) {
85
108
  worktreeId: input.worktreeId,
86
109
  });
87
110
  }
88
- if (!(await isDirectory(record.absolutePath))) {
89
- throw providerError('WORKTREE_NOT_FOUND', `Worktree directory is unavailable: ${record.absolutePath}`, {
111
+ if (!(await isDirectory(gitWorktreeRoot(record)))) {
112
+ throw providerError('WORKTREE_NOT_FOUND', `Worktree directory is unavailable: ${gitWorktreeRoot(record)}`, {
90
113
  workspaceId: input.workspaceId,
91
114
  worktreeId: input.worktreeId,
92
- absolutePath: record.absolutePath,
115
+ absolutePath: gitWorktreeRoot(record),
93
116
  });
94
117
  }
95
118
  const repositoryRoot = context.git.resolveRepositoryRoot
96
119
  ? await context.git.resolveRepositoryRoot(workspace.rootPath, { signal: context.signal })
97
120
  : workspace.rootPath;
98
- const live = await findLiveWorktree(await context.git.listWorktrees(repositoryRoot, { signal: context.signal }), record.absolutePath);
121
+ const live = await findLiveWorktree(await context.git.listWorktrees(repositoryRoot, { signal: context.signal }), gitWorktreeRoot(record));
99
122
  if (!live) {
100
- throw providerError('WORKTREE_NOT_FOUND', `Git Worktree registration is unavailable: ${record.absolutePath}`, {
123
+ throw providerError('WORKTREE_NOT_FOUND', `Git Worktree registration is unavailable: ${gitWorktreeRoot(record)}`, {
101
124
  workspaceId: input.workspaceId,
102
125
  worktreeId: input.worktreeId,
103
- absolutePath: record.absolutePath,
126
+ absolutePath: gitWorktreeRoot(record),
104
127
  });
105
128
  }
106
129
  return {
@@ -109,31 +132,16 @@ async function resolveWorktree(context, input) {
109
132
  workspaceRoot: workspace.rootPath,
110
133
  repositoryRoot,
111
134
  record,
112
- live,
135
+ live: live.headCommit === undefined && context.git.resolveCommit
136
+ ? { ...live, headCommit: await context.git.resolveCommit(gitWorktreeRoot(record), 'HEAD', { signal: context.signal }) }
137
+ : live,
113
138
  },
114
139
  };
115
140
  }
116
- /** True when a branch name can be safely handed to Git as a ref argument. */
117
- function isSafeBranchName(branch) {
118
- if (branch.length === 0 || branch.startsWith('-'))
119
- return false;
120
- // Only a local branch short name may be selected. A full ref path is an
121
- // arbitrary-ref attempt and is rejected instead of degrading to unavailable.
122
- if (branch.startsWith('refs/'))
123
- return false;
124
- for (const character of branch) {
125
- const code = character.codePointAt(0) ?? 0;
126
- if (code < 0x20 || code === 0x7f)
127
- return false;
128
- }
129
- return true;
130
- }
131
141
  /**
132
- * Resolve one local branch tip for the Dashboard baseline. The branch must exist
133
- * under `refs/heads/`, so tags, remote-tracking branches, and arbitrary refs are
134
- * rejected even though the browser may send any string.
142
+ * Resolve only enumerated branch identities. Tags and arbitrary revision expressions are rejected.
135
143
  */
136
- async function resolveLocalBranchCommit(context, resolved, baseBranch, options = {}) {
144
+ async function resolveBranchCommit(context, resolved, baseBranch, options = {}) {
137
145
  const unavailable = () => {
138
146
  throw providerError('WORKTREE_STATE_CONFLICT', 'Selected baseline branch is unavailable: ' + baseBranch, {
139
147
  worktreeId: resolved.record.worktreeId,
@@ -142,20 +150,20 @@ async function resolveLocalBranchCommit(context, resolved, baseBranch, options =
142
150
  };
143
151
  // An unsafe ref is always a hard failure: arbitrary refs must never resolve,
144
152
  // even for a read that is allowed to degrade to an unavailable projection.
145
- if (!isSafeBranchName(baseBranch))
153
+ if (!isSafeBranchIdentity(baseBranch))
146
154
  unavailable();
147
- const listBranches = gitRead(context, 'listBranches', resolved.record.worktreeId);
148
155
  const resolveCommit = gitRead(context, 'resolveCommit', resolved.record.worktreeId);
149
- const branches = await listBranches(resolved.repositoryRoot, { signal: context.signal });
156
+ const branches = await readBranchFacts(context.git, resolved.repositoryRoot, { signal: context.signal });
157
+ const branch = findBranchIdentity(branches, baseBranch);
150
158
  // A baseline branch that no longer exists is an expected unavailable state for
151
159
  // reads, so the Dashboard can show an honest empty projection instead of a
152
160
  // generic Git failure. Writes keep the strict behaviour.
153
- if (!branches.includes(baseBranch)) {
161
+ if (branch === undefined) {
154
162
  if (options.allowUnavailable === true)
155
163
  return undefined;
156
164
  unavailable();
157
165
  }
158
- const commit = await resolveCommit(resolved.record.absolutePath, baseBranch, {
166
+ const commit = await resolveCommit(gitWorktreeRoot(resolved.record), branch?.ref ?? baseBranch, {
159
167
  signal: context.signal,
160
168
  });
161
169
  if (!COMMIT_PATTERN.test(commit)) {
@@ -164,25 +172,26 @@ async function resolveLocalBranchCommit(context, resolved, baseBranch, options =
164
172
  baseBranch,
165
173
  });
166
174
  }
167
- return commit;
175
+ return { commit, branch: branch };
168
176
  }
169
177
  async function resolveSelectedBaseline(context, resolved, rawBranch) {
170
178
  const baseBranch = rawBranch.trim();
171
179
  if (baseBranch.length === 0)
172
180
  return undefined;
173
181
  // A vanished baseline branch degrades to an unavailable projection for reads.
174
- const commit = await resolveLocalBranchCommit(context, resolved, baseBranch, {
182
+ const selected = await resolveBranchCommit(context, resolved, baseBranch, {
175
183
  allowUnavailable: true,
176
184
  });
177
- if (commit === undefined)
185
+ if (selected === undefined)
178
186
  return undefined;
187
+ const { commit } = selected;
179
188
  // A selected branch can move after the Worktree was created. Match GitHub's
180
189
  // pull-request range by diffing from the two heads' merge base to Worktree
181
190
  // HEAD, while retaining the selected branch tip for ahead/behind counts.
182
191
  const headCommit = await baselineHeadCommit(context, resolved);
183
192
  const findMergeBase = gitReadOptional(context, 'findMergeBase');
184
193
  const mergeBase = headCommit !== undefined && findMergeBase !== undefined
185
- ? await findMergeBase(resolved.record.absolutePath, commit, headCommit, { signal: context.signal })
194
+ ? await findMergeBase(gitWorktreeRoot(resolved.record), commit, headCommit, { signal: context.signal })
186
195
  : undefined;
187
196
  if (mergeBase !== undefined && !COMMIT_PATTERN.test(mergeBase)) {
188
197
  throw providerError('GIT_OPERATION_FAILED', 'Git returned an invalid selected branch merge base', {
@@ -200,14 +209,14 @@ async function resolveSelectedBaseline(context, resolved, rawBranch) {
200
209
  treeBaseCommit: mergeBase ?? commit,
201
210
  };
202
211
  }
203
- /** Persist a user-selected local branch as the Worktree's Dashboard baseline. */
212
+ /** Persist a user-selected local or fetched remote branch as the Dashboard baseline. */
204
213
  export async function updateWorktreeBaseBranch(context, input) {
205
214
  if (typeof input.baseBranch !== 'string') {
206
215
  throw providerError('WORKTREE_STATE_CONFLICT', 'The baseline branch must be a string', {
207
216
  worktreeId: input.worktreeId,
208
217
  });
209
218
  }
210
- const baseBranch = input.baseBranch.trim();
219
+ let baseBranch = input.baseBranch.trim();
211
220
  if (baseBranch.length === 0) {
212
221
  throw providerError('WORKTREE_STATE_CONFLICT', 'The baseline branch cannot be empty', {
213
222
  worktreeId: input.worktreeId,
@@ -219,7 +228,7 @@ export async function updateWorktreeBaseBranch(context, input) {
219
228
  });
220
229
  }
221
230
  const expectedBaseBranch = input.expectedBaseBranch?.trim() || undefined;
222
- const resolved = await resolveWorktree(context, input);
231
+ const resolved = await resolveWorktree(context, input, false);
223
232
  if (resolved.main) {
224
233
  throw providerError('WORKTREE_STATE_CONFLICT', 'The local Workspace has no editable baseline', {
225
234
  workspaceId: input.workspaceId,
@@ -234,7 +243,13 @@ export async function updateWorktreeBaseBranch(context, input) {
234
243
  }
235
244
  // Resolve the replacement branch against the pinned repository root before the
236
245
  // sidecar mutation, so an unavailable branch fails closed without a write.
237
- await resolveLocalBranchCommit(context, resolved.value, baseBranch);
246
+ const selected = await resolveBranchCommit(context, resolved.value, baseBranch);
247
+ if (selected.branch.kind !== 'remote' && selected.branch.name === currentBranch) {
248
+ throw providerError('WORKTREE_STATE_CONFLICT', 'The baseline branch cannot be the current Worktree branch', {
249
+ worktreeId: input.worktreeId, baseBranch,
250
+ });
251
+ }
252
+ baseBranch = canonicalBranchIdentity(selected.branch, baseBranch);
238
253
  return context.sidecar.mutate(input.workspaceId, (snapshot) => {
239
254
  if (snapshot.pendingOperation !== undefined || (snapshot.recoveryIssues?.length ?? 0) > 0) {
240
255
  throw providerError('WORKTREE_RECOVERY_REQUIRED', 'Workspace Worktree state needs recovery: ' + input.workspaceId, { workspaceId: input.workspaceId });
@@ -284,7 +299,7 @@ async function resolveBaseline(context, resolved, requestedBaseBranch) {
284
299
  });
285
300
  }
286
301
  const commit = context.git.resolveCommit
287
- ? await context.git.resolveCommit(record.absolutePath, record.baseCommit, { signal: context.signal })
302
+ ? await context.git.resolveCommit(gitWorktreeRoot(record), record.baseCommit, { signal: context.signal })
288
303
  : record.baseCommit;
289
304
  return {
290
305
  baseline: {
@@ -305,7 +320,7 @@ async function resolveBaseline(context, resolved, requestedBaseBranch) {
305
320
  if (currentBranch === undefined || currentBranch === record.baseBranch || context.git.findMergeBase === undefined) {
306
321
  return undefined;
307
322
  }
308
- const commit = await context.git.findMergeBase(record.absolutePath, record.baseBranch, 'HEAD', { signal: context.signal });
323
+ const commit = await context.git.findMergeBase(gitWorktreeRoot(record), record.baseBranch, 'HEAD', { signal: context.signal });
309
324
  if (commit === undefined)
310
325
  return undefined;
311
326
  if (!COMMIT_PATTERN.test(commit)) {
@@ -326,7 +341,7 @@ async function resolveBaseline(context, resolved, requestedBaseBranch) {
326
341
  async function requireBaseline(context, resolved, requestedBaseBranch) {
327
342
  const baseline = await resolveBaseline(context, resolved, requestedBaseBranch);
328
343
  if (baseline === undefined) {
329
- throw providerError('WORKTREE_STATE_CONFLICT', 'Select a local baseline branch before reading Git changes', { worktreeId: resolved.record.worktreeId });
344
+ throw providerError('WORKTREE_STATE_CONFLICT', 'Select a baseline branch before reading Git changes', { worktreeId: resolved.record.worktreeId });
330
345
  }
331
346
  return baseline;
332
347
  }
@@ -336,7 +351,7 @@ async function baselineHeadCommit(context, resolved) {
336
351
  const resolveCommit = gitReadOptional(context, 'resolveCommit');
337
352
  return resolveCommit === undefined
338
353
  ? undefined
339
- : await resolveCommit(resolved.record.absolutePath, 'HEAD', { signal: context.signal });
354
+ : await resolveCommit(gitWorktreeRoot(resolved.record), 'HEAD', { signal: context.signal });
340
355
  }
341
356
  /** Count commits unique to each head for one resolved comparison boundary. */
342
357
  async function readCommitDivergence(context, resolved, comparison, head) {
@@ -345,18 +360,14 @@ async function readCommitDivergence(context, resolved, comparison, head) {
345
360
  return undefined;
346
361
  // Count each branch from its current tip. The tree boundary may be the
347
362
  // merge base, but ahead/behind must include commits unique to both heads.
348
- return getCommitDivergence(resolved.record.absolutePath, comparison.baseHeadCommit, head, { signal: context.signal });
363
+ return getCommitDivergence(gitWorktreeRoot(resolved.record), comparison.baseHeadCommit, head, { signal: context.signal });
349
364
  }
350
365
  /**
351
366
  * Authorize commit SHAs against one pinned comparison projection.
352
367
  *
353
- * One bounded `listCommits` read yields exactly the authorized set: commits
354
- * reachable from the Worktree HEAD and not reachable from the resolved baseline
355
- * head. That is the same membership the previous per-SHA ancestry walks proved,
356
- * but a wide multi-commit selection now costs one projection read instead of
357
- * several Git processes per candidate SHA. The visible projection is therefore
358
- * the authorization boundary, matching the truncated 200-commit history the
359
- * browser can actually select from.
368
+ * Candidates must be reachable from HEAD and excluded from baseline ancestry,
369
+ * independently of which 50-commit page the browser has loaded. Legacy adapters
370
+ * without the membership capability retain bounded projection authorization.
360
371
  */
361
372
  async function authorizeCommits(context, resolved, comparison, candidates) {
362
373
  const worktreeId = resolved.record.worktreeId;
@@ -368,8 +379,13 @@ async function authorizeCommits(context, resolved, comparison, candidates) {
368
379
  }
369
380
  return candidate;
370
381
  });
382
+ const headCommit = resolved.live.headCommit;
383
+ if (headCommit !== undefined && (context.git.containsCommits || context.git.containsCommit)) {
384
+ await authorizeMembership(context, gitWorktreeRoot(resolved.record), worktreeId, requested, headCommit, comparison.baseHeadCommit);
385
+ return requested;
386
+ }
371
387
  const listCommits = gitRead(context, 'listCommits', worktreeId);
372
- const history = await listCommits(resolved.record.absolutePath, comparison.baseHeadCommit, {
388
+ const history = await listCommits(gitWorktreeRoot(resolved.record), comparison.baseHeadCommit, {
373
389
  signal: context.signal,
374
390
  });
375
391
  const members = new Set(history.commits.map((commit) => commit.sha));
@@ -383,6 +399,22 @@ async function authorizeCommits(context, resolved, comparison, candidates) {
383
399
  }
384
400
  return requested;
385
401
  }
402
+ /** Share a fixed checkout identity across all membership checks in a request. */
403
+ async function authorizeMembership(context, root, worktreeId, commits, headCommit, baseCommit) {
404
+ const options = { signal: context.signal };
405
+ const allowed = context.git.containsCommits
406
+ ? await context.git.containsCommits(root, commits, headCommit, baseCommit, options)
407
+ : await (async () => {
408
+ for (const commit of commits) {
409
+ if (!await context.git.containsCommit(root, commit, headCommit, baseCommit, options))
410
+ return false;
411
+ }
412
+ return true;
413
+ })();
414
+ if (!allowed) {
415
+ throw providerError('WORKTREE_STATE_CONFLICT', 'The requested commits are outside this checkout history', { worktreeId });
416
+ }
417
+ }
386
418
  async function authorizeCommit(context, resolved, commitInput, requestedBaseBranch) {
387
419
  const comparison = await requireBaseline(context, resolved, requestedBaseBranch);
388
420
  const [commit] = await authorizeCommits(context, resolved, comparison, [commitInput]);
@@ -395,13 +427,13 @@ async function authorizeWorkingTree(context, resolved, requestedBaseBranch) {
395
427
  await requireBaseline(context, resolved, requestedBaseBranch);
396
428
  }
397
429
  /** Read Main's bounded HEAD history and expose live Workspace-root changes first. */
398
- async function listMainCommits(context, workspaceRoot, worktreeId) {
430
+ async function listMainCommits(context, workspaceRoot, worktreeId, offset = 0) {
399
431
  const listCommits = gitRead(context, 'listCommits', worktreeId);
400
432
  const readWorkingTreePaths = gitReadOptional(context, 'listWorkingTreeChangedPaths')
401
433
  ?? gitReadOptional(context, 'listWorkingTreeFiles');
402
434
  const [history, workingTreeFiles] = await Promise.all([
403
- listCommits(workspaceRoot, undefined, { signal: context.signal }),
404
- readWorkingTreePaths === undefined
435
+ listCommits(workspaceRoot, undefined, { signal: context.signal, offset }),
436
+ offset > 0 || readWorkingTreePaths === undefined
405
437
  ? Promise.resolve({ files: [], truncated: false })
406
438
  : readWorkingTreePaths(workspaceRoot, { signal: context.signal }),
407
439
  ]);
@@ -413,12 +445,16 @@ async function listMainCommits(context, workspaceRoot, worktreeId) {
413
445
  : history.commits,
414
446
  };
415
447
  }
416
- async function authorizeMainCommit(context, workspaceRoot, worktreeId, commitInput) {
448
+ async function authorizeMainCommit(context, workspaceRoot, worktreeId, commitInput, headCommit) {
417
449
  if (typeof commitInput !== 'string' || !COMMIT_PATTERN.test(commitInput)) {
418
450
  throw providerError('WORKTREE_STATE_CONFLICT', 'The requested commit is not a valid commit SHA', {
419
451
  worktreeId,
420
452
  });
421
453
  }
454
+ if (headCommit !== undefined && (context.git.containsCommits || context.git.containsCommit)) {
455
+ await authorizeMembership(context, workspaceRoot, worktreeId, [commitInput], headCommit);
456
+ return commitInput;
457
+ }
422
458
  const history = await listMainCommits(context, workspaceRoot, worktreeId);
423
459
  if (!history.commits.some((commit) => commit.sha === commitInput)) {
424
460
  throw providerError('WORKTREE_STATE_CONFLICT', 'The requested commit is outside the visible Main history', {
@@ -429,7 +465,7 @@ async function authorizeMainCommit(context, workspaceRoot, worktreeId, commitInp
429
465
  return commitInput;
430
466
  }
431
467
  const MAX_AGGREGATE_COMMITS = 200;
432
- async function authorizeMainAggregate(context, workspaceRoot, worktreeId, selection) {
468
+ async function authorizeMainAggregate(context, workspaceRoot, worktreeId, selection, headCommit) {
433
469
  if (selection.kind !== 'commits') {
434
470
  throw providerError('WORKTREE_STATE_CONFLICT', 'Main Git supports committed selections only', {
435
471
  worktreeId,
@@ -453,6 +489,10 @@ async function authorizeMainAggregate(context, workspaceRoot, worktreeId, select
453
489
  worktreeId,
454
490
  });
455
491
  }
492
+ if (headCommit !== undefined && (context.git.containsCommits || context.git.containsCommit)) {
493
+ await authorizeMembership(context, workspaceRoot, worktreeId, requested, headCommit);
494
+ return { selection: { kind: 'commits', commits: requested }, commits: requested };
495
+ }
456
496
  const history = await listMainCommits(context, workspaceRoot, worktreeId);
457
497
  const members = new Set(history.commits
458
498
  .filter((commit) => commit.kind !== 'working-tree')
@@ -471,10 +511,26 @@ async function authorizeMainAggregate(context, workspaceRoot, worktreeId, select
471
511
  };
472
512
  }
473
513
  export async function listWorktreeCommits(context, input) {
514
+ const offset = input.offset ?? 0;
515
+ if (!Number.isSafeInteger(offset) || offset < 0 ||
516
+ (offset > 0 && (input.expectedHeadCommit === undefined ||
517
+ (input.baseBranch !== undefined && input.expectedBaselineCommit === undefined)))) {
518
+ throw providerError('WORKTREE_STATE_CONFLICT', 'Invalid history page', { worktreeId: input.worktreeId });
519
+ }
520
+ const checkProjection = (head, baseline) => {
521
+ if ((input.expectedHeadCommit !== undefined && input.expectedHeadCommit !== head) ||
522
+ (input.expectedBaselineCommit !== undefined && input.expectedBaselineCommit !== baseline)) {
523
+ throw providerError('WORKTREE_STATE_CONFLICT', 'Git history changed; refresh before loading more', {
524
+ worktreeId: input.worktreeId,
525
+ });
526
+ }
527
+ };
474
528
  const resolved = await resolveWorktree(context, input);
475
529
  if (resolved.main) {
476
- const history = await listMainCommits(context, resolved.workspaceRoot, input.worktreeId);
530
+ const history = await listMainCommits(context, resolved.repositoryRoot, input.worktreeId, offset);
531
+ checkProjection(history.headCommit);
477
532
  return {
533
+ ...(history.nextOffset === undefined ? {} : { nextOffset: history.nextOffset }),
478
534
  headCommit: history.headCommit,
479
535
  commits: history.commits,
480
536
  truncated: history.truncated,
@@ -487,17 +543,23 @@ export async function listWorktreeCommits(context, input) {
487
543
  ? 'baseline-unselected'
488
544
  : 'baseline-unknown');
489
545
  }
546
+ if (offset > 0 && input.expectedBaselineCommit === undefined) {
547
+ throw providerError('WORKTREE_STATE_CONFLICT', 'A comparison page requires its baseline commit', {
548
+ worktreeId: input.worktreeId,
549
+ });
550
+ }
490
551
  const listCommits = gitRead(context, 'listCommits', input.worktreeId);
491
552
  // The working-tree entry only needs the changed-path projection here; its file
492
553
  // list and line counts are read on demand when the entry is selected.
493
554
  const readWorkingTreePaths = gitReadOptional(context, 'listWorkingTreeChangedPaths')
494
555
  ?? gitReadOptional(context, 'listWorkingTreeFiles');
495
556
  const [history, workingTreeFiles] = await Promise.all([
496
- listCommits(resolved.value.record.absolutePath, baseline.baseHeadCommit, { signal: context.signal }),
497
- readWorkingTreePaths === undefined
557
+ listCommits(gitWorktreeRoot(resolved.value.record), baseline.baseHeadCommit, { signal: context.signal, offset }),
558
+ offset > 0 || readWorkingTreePaths === undefined
498
559
  ? Promise.resolve({ files: [], truncated: false })
499
- : readWorkingTreePaths(resolved.value.record.absolutePath, { signal: context.signal }),
560
+ : readWorkingTreePaths(gitWorktreeRoot(resolved.value.record), { signal: context.signal }),
500
561
  ]);
562
+ checkProjection(history.headCommit, baseline.baseline.commit);
501
563
  const divergence = await readCommitDivergence(context, resolved.value, baseline, history.headCommit);
502
564
  return {
503
565
  ...history,
@@ -609,7 +671,7 @@ async function authorizeLiveSummaryHead(context, resolved) {
609
671
  const resolveCommit = gitReadOptional(context, 'resolveCommit');
610
672
  if (resolveCommit === undefined)
611
673
  return;
612
- const currentHead = await resolveCommit(resolved.record.absolutePath, 'HEAD', { signal: context.signal });
674
+ const currentHead = await resolveCommit(gitWorktreeRoot(resolved.record), 'HEAD', { signal: context.signal });
613
675
  if (!COMMIT_PATTERN.test(currentHead)) {
614
676
  throw providerError('GIT_OPERATION_FAILED', 'Git returned an invalid live Worktree HEAD', {
615
677
  worktreeId: resolved.record.worktreeId,
@@ -620,19 +682,19 @@ async function listSummaryFiles(context, resolved, selection, baseCommit, headCo
620
682
  if (selection.includeWorkingTree === true) {
621
683
  const listWorkingTreeDiffFiles = gitRead(context, 'listWorkingTreeDiffFiles', resolved.record.worktreeId);
622
684
  await authorizeLiveSummaryHead(context, resolved);
623
- return listWorkingTreeDiffFiles(resolved.record.absolutePath, baseCommit, { signal: context.signal });
685
+ return listWorkingTreeDiffFiles(gitWorktreeRoot(resolved.record), baseCommit, { signal: context.signal });
624
686
  }
625
687
  const listDiffFiles = gitRead(context, 'listDiffFiles', resolved.record.worktreeId);
626
- return listDiffFiles(resolved.record.absolutePath, baseCommit, headCommit, { signal: context.signal });
688
+ return listDiffFiles(gitWorktreeRoot(resolved.record), baseCommit, headCommit, { signal: context.signal });
627
689
  }
628
690
  async function readSummaryFileDiff(context, resolved, selection, baseCommit, headCommit, filePath) {
629
691
  if (selection.includeWorkingTree === true) {
630
692
  const readWorkingTreeDiffFileDiff = gitRead(context, 'readWorkingTreeDiffFileDiff', resolved.record.worktreeId);
631
693
  await authorizeLiveSummaryHead(context, resolved);
632
- return readWorkingTreeDiffFileDiff(resolved.record.absolutePath, baseCommit, filePath, { signal: context.signal });
694
+ return readWorkingTreeDiffFileDiff(gitWorktreeRoot(resolved.record), baseCommit, filePath, { signal: context.signal });
633
695
  }
634
696
  const readDiffFileDiff = gitRead(context, 'readDiffFileDiff', resolved.record.worktreeId);
635
- return readDiffFileDiff(resolved.record.absolutePath, baseCommit, headCommit, filePath, { signal: context.signal });
697
+ return readDiffFileDiff(gitWorktreeRoot(resolved.record), baseCommit, headCommit, filePath, { signal: context.signal });
636
698
  }
637
699
  async function selectedAggregateFileDiff(context, absolutePath, worktreeId, selection, commits, requestedPath) {
638
700
  if (requestedPath.length === 0) {
@@ -671,17 +733,17 @@ async function selectedAggregateFileDiff(context, absolutePath, worktreeId, sele
671
733
  segments,
672
734
  };
673
735
  }
674
- async function aggregateMainFileDiff(context, workspaceRoot, repositoryRoot, worktreeId, selection, requestedPath) {
736
+ async function aggregateMainFileDiff(context, workspaceRoot, repositoryRoot, worktreeId, selection, requestedPath, headCommit) {
675
737
  if (typeof requestedPath !== 'string' || requestedPath.length === 0) {
676
738
  throw providerError('WORKTREE_STATE_CONFLICT', 'A changed file path is required', {
677
739
  worktreeId,
678
740
  });
679
741
  }
680
- const authorized = await authorizeMainAggregate(context, workspaceRoot, worktreeId, selection);
742
+ const authorized = await authorizeMainAggregate(context, workspaceRoot, worktreeId, selection, headCommit);
681
743
  return selectedAggregateFileDiff(context, repositoryRoot, worktreeId, authorized.selection, authorized.commits, requestedPath);
682
744
  }
683
- async function listMainAggregateFiles(context, workspaceRoot, repositoryRoot, worktreeId, selection) {
684
- const authorized = await authorizeMainAggregate(context, workspaceRoot, worktreeId, selection);
745
+ async function listMainAggregateFiles(context, workspaceRoot, repositoryRoot, worktreeId, selection, headCommit) {
746
+ const authorized = await authorizeMainAggregate(context, workspaceRoot, worktreeId, selection, headCommit);
685
747
  const groups = await selectedCommitFiles(context, repositoryRoot, worktreeId, authorized.commits);
686
748
  return {
687
749
  commit: authorized.commits[0],
@@ -701,7 +763,7 @@ async function listAggregateFiles(context, resolved, selection, requestedBaseBra
701
763
  ...(read.truncated ? { truncated: true } : {}),
702
764
  };
703
765
  }
704
- const groups = await selectedCommitFiles(context, resolved.record.absolutePath, resolved.record.worktreeId, authorized.commits);
766
+ const groups = await selectedCommitFiles(context, gitWorktreeRoot(resolved.record), resolved.record.worktreeId, authorized.commits);
705
767
  return {
706
768
  commit: authorized.commits[0],
707
769
  selection: authorized.selection,
@@ -733,25 +795,24 @@ async function aggregateFileDiff(context, resolved, selection, requestedPath, re
733
795
  selection: authorized.selection,
734
796
  };
735
797
  }
736
- return selectedAggregateFileDiff(context, resolved.record.absolutePath, resolved.record.worktreeId, authorized.selection, authorized.commits, requestedPath);
798
+ return selectedAggregateFileDiff(context, gitWorktreeRoot(resolved.record), resolved.record.worktreeId, authorized.selection, authorized.commits, requestedPath);
737
799
  }
738
- export async function listWorktreeCommitFiles(context, input) {
739
- const resolved = await resolveWorktree(context, input);
800
+ async function listCheckoutCommitFiles(context, input, resolved) {
740
801
  const requested = requestedDiff(input, input.worktreeId);
741
802
  if (resolved.main) {
742
803
  if (requested.kind === 'aggregate') {
743
- return listMainAggregateFiles(context, resolved.workspaceRoot, resolved.repositoryRoot, input.worktreeId, requested.selection);
804
+ return listMainAggregateFiles(context, resolved.repositoryRoot, resolved.repositoryRoot, input.worktreeId, requested.selection, resolved.headCommit);
744
805
  }
745
806
  if (requested.commit === WORKTREE_GIT_WORKING_TREE) {
746
807
  const listWorkingTreeFiles = gitRead(context, 'listWorkingTreeFiles', input.worktreeId);
747
- const read = await listWorkingTreeFiles(resolved.workspaceRoot, { signal: context.signal });
808
+ const read = await listWorkingTreeFiles(resolved.repositoryRoot, { signal: context.signal });
748
809
  return {
749
810
  commit: WORKTREE_GIT_WORKING_TREE,
750
811
  files: read.files,
751
812
  ...(read.truncated ? { truncated: true } : {}),
752
813
  };
753
814
  }
754
- const commit = await authorizeMainCommit(context, resolved.workspaceRoot, input.worktreeId, requested.commit);
815
+ const commit = await authorizeMainCommit(context, resolved.repositoryRoot, input.worktreeId, requested.commit, resolved.headCommit);
755
816
  const listCommitFiles = gitRead(context, 'listCommitFiles', input.worktreeId);
756
817
  const read = await listCommitFiles(resolved.repositoryRoot, commit, { signal: context.signal });
757
818
  return {
@@ -767,7 +828,7 @@ export async function listWorktreeCommitFiles(context, input) {
767
828
  if (commit === WORKTREE_GIT_WORKING_TREE) {
768
829
  await authorizeWorkingTree(context, resolved.value, input.baseBranch);
769
830
  const listWorkingTreeFiles = gitRead(context, 'listWorkingTreeFiles', input.worktreeId);
770
- const read = await listWorkingTreeFiles(resolved.value.record.absolutePath, { signal: context.signal });
831
+ const read = await listWorkingTreeFiles(gitWorktreeRoot(resolved.value.record), { signal: context.signal });
771
832
  return {
772
833
  commit: WORKTREE_GIT_WORKING_TREE,
773
834
  files: read.files,
@@ -776,15 +837,14 @@ export async function listWorktreeCommitFiles(context, input) {
776
837
  }
777
838
  const authorized = await authorizeCommit(context, resolved.value, commit, input.baseBranch);
778
839
  const listCommitFiles = gitRead(context, 'listCommitFiles', input.worktreeId);
779
- const read = await listCommitFiles(resolved.value.record.absolutePath, authorized.commit, { signal: context.signal });
840
+ const read = await listCommitFiles(gitWorktreeRoot(resolved.value.record), authorized.commit, { signal: context.signal });
780
841
  return {
781
842
  commit: authorized.commit,
782
843
  files: read.files,
783
844
  ...(read.truncated ? { truncated: true } : {}),
784
845
  };
785
846
  }
786
- export async function getWorktreeCommitFileDiff(context, input) {
787
- const resolved = await resolveWorktree(context, input);
847
+ async function getCheckoutCommitFileDiff(context, input, resolved) {
788
848
  const requested = requestedDiff(input, input.worktreeId);
789
849
  if (resolved.main) {
790
850
  if (requested.kind === 'aggregate') {
@@ -793,7 +853,7 @@ export async function getWorktreeCommitFileDiff(context, input) {
793
853
  worktreeId: input.worktreeId,
794
854
  });
795
855
  }
796
- return aggregateMainFileDiff(context, resolved.workspaceRoot, resolved.repositoryRoot, input.worktreeId, requested.selection, input.path);
856
+ return aggregateMainFileDiff(context, resolved.repositoryRoot, resolved.repositoryRoot, input.worktreeId, requested.selection, input.path, resolved.headCommit);
797
857
  }
798
858
  if (typeof input.path !== 'string' || input.path.length === 0) {
799
859
  throw providerError('WORKTREE_STATE_CONFLICT', 'A changed file path is required', {
@@ -804,7 +864,7 @@ export async function getWorktreeCommitFileDiff(context, input) {
804
864
  const readWorkingTreeFileDiff = gitRead(context, 'readWorkingTreeFileDiff', input.worktreeId);
805
865
  const readChangedPaths = gitReadOptional(context, 'listWorkingTreeChangedPaths')
806
866
  ?? gitRead(context, 'listWorkingTreeFiles', input.worktreeId);
807
- const readPaths = await readChangedPaths(resolved.workspaceRoot, { signal: context.signal });
867
+ const readPaths = await readChangedPaths(resolved.repositoryRoot, { signal: context.signal });
808
868
  const changedFile = findChangedFile(readPaths.files, input.path);
809
869
  if (changedFile === undefined) {
810
870
  throw providerError('WORKTREE_STATE_CONFLICT', 'The requested path is not changed in the Main working tree', {
@@ -813,10 +873,10 @@ export async function getWorktreeCommitFileDiff(context, input) {
813
873
  path: input.path,
814
874
  });
815
875
  }
816
- const diff = await readWorkingTreeFileDiff(resolved.workspaceRoot, changedFile.path, { signal: context.signal });
876
+ const diff = await readWorkingTreeFileDiff(resolved.repositoryRoot, changedFile.path, { signal: context.signal });
817
877
  return { ...diff, commit: WORKTREE_GIT_WORKING_TREE, path: input.path };
818
878
  }
819
- const commit = await authorizeMainCommit(context, resolved.workspaceRoot, input.worktreeId, requested.commit);
879
+ const commit = await authorizeMainCommit(context, resolved.repositoryRoot, input.worktreeId, requested.commit, resolved.headCommit);
820
880
  const listCommitFiles = gitRead(context, 'listCommitFiles', input.worktreeId);
821
881
  const filesRead = await listCommitFiles(resolved.repositoryRoot, commit, { signal: context.signal });
822
882
  const changedFile = findChangedFile(filesRead.files, input.path);
@@ -848,7 +908,7 @@ export async function getWorktreeCommitFileDiff(context, input) {
848
908
  // untracked file on each file click.
849
909
  const readChangedPaths = gitReadOptional(context, 'listWorkingTreeChangedPaths')
850
910
  ?? gitRead(context, 'listWorkingTreeFiles', input.worktreeId);
851
- const readPaths = await readChangedPaths(resolved.value.record.absolutePath, { signal: context.signal });
911
+ const readPaths = await readChangedPaths(gitWorktreeRoot(resolved.value.record), { signal: context.signal });
852
912
  const changedFile = findChangedFile(readPaths.files, input.path);
853
913
  if (changedFile === undefined) {
854
914
  throw providerError('WORKTREE_STATE_CONFLICT', 'The requested path is not changed in the working tree', {
@@ -857,7 +917,7 @@ export async function getWorktreeCommitFileDiff(context, input) {
857
917
  path: input.path,
858
918
  });
859
919
  }
860
- const diff = await readWorkingTreeFileDiff(resolved.value.record.absolutePath, changedFile.path, { signal: context.signal });
920
+ const diff = await readWorkingTreeFileDiff(gitWorktreeRoot(resolved.value.record), changedFile.path, { signal: context.signal });
861
921
  return {
862
922
  ...diff,
863
923
  commit: WORKTREE_GIT_WORKING_TREE,
@@ -869,7 +929,7 @@ export async function getWorktreeCommitFileDiff(context, input) {
869
929
  const listCommitFiles = gitRead(context, 'listCommitFiles', input.worktreeId);
870
930
  // The changed-file projection is the authorization boundary for the path, so
871
931
  // the diff is only read for an exact member of that projection.
872
- const filesRead = await listCommitFiles(resolved.value.record.absolutePath, authorized.commit, { signal: context.signal });
932
+ const filesRead = await listCommitFiles(gitWorktreeRoot(resolved.value.record), authorized.commit, { signal: context.signal });
873
933
  const changedFile = findChangedFile(filesRead.files, input.path);
874
934
  if (changedFile === undefined) {
875
935
  throw providerError('WORKTREE_STATE_CONFLICT', 'The requested path is not changed by this commit', {
@@ -878,11 +938,45 @@ export async function getWorktreeCommitFileDiff(context, input) {
878
938
  path: input.path,
879
939
  });
880
940
  }
881
- const diff = await readCommitFileDiff(resolved.value.record.absolutePath, authorized.commit, changedFile.path, { signal: context.signal });
941
+ const diff = await readCommitFileDiff(gitWorktreeRoot(resolved.value.record), authorized.commit, changedFile.path, { signal: context.signal });
882
942
  return {
883
943
  ...diff,
884
944
  commit: authorized.commit,
885
945
  path: input.path,
886
946
  };
887
947
  }
948
+ async function pathsFor(resolved) {
949
+ if (resolved.main)
950
+ return workspaceGitPaths(resolved.repositoryRoot, resolved.workspaceRoot);
951
+ const { record, workspaceRoot, repositoryRoot } = resolved.value;
952
+ const projected = await projectWorktreePath(record, workspaceRoot, repositoryRoot);
953
+ return workspaceGitPaths(gitWorktreeRoot(projected), projected.absolutePath);
954
+ }
955
+ /** Reject a projection if checkout HEAD moved during authorization or file reads. */
956
+ async function assertCheckoutHead(context, resolved, worktreeId) {
957
+ const headCommit = resolved.main ? resolved.headCommit : resolved.value.live.headCommit;
958
+ if (headCommit === undefined || context.git.resolveCommit === undefined)
959
+ return;
960
+ const root = resolved.main ? resolved.repositoryRoot : gitWorktreeRoot(resolved.value.record);
961
+ const current = await context.git.resolveCommit(root, 'HEAD', { signal: context.signal });
962
+ if (current !== headCommit) {
963
+ throw providerError('WORKTREE_STATE_CONFLICT', 'Checkout HEAD changed; refresh Git data', { worktreeId });
964
+ }
965
+ }
966
+ /** Public changed-file identities always start at the Workspace directory, including ../ siblings. */
967
+ export async function listWorktreeCommitFiles(context, input) {
968
+ const resolved = await resolveWorktree(context, input);
969
+ const paths = await pathsFor(resolved);
970
+ const read = await listCheckoutCommitFiles(context, input, resolved);
971
+ await assertCheckoutHead(context, resolved, input.worktreeId);
972
+ return paths.projectFiles(read);
973
+ }
974
+ /** Translate exactly once, then keep the existing changed-file authorization in checkout coordinates. */
975
+ export async function getWorktreeCommitFileDiff(context, input) {
976
+ const resolved = await resolveWorktree(context, input);
977
+ const paths = await pathsFor(resolved);
978
+ const diff = await getCheckoutCommitFileDiff(context, { ...input, path: paths.toCheckout(input.path) }, resolved);
979
+ await assertCheckoutHead(context, resolved, input.worktreeId);
980
+ return { ...diff, path: input.path };
981
+ }
888
982
  //# sourceMappingURL=manager-git-history.js.map