@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.
- package/README.md +314 -43
- package/README.zh.md +263 -37
- package/assets/screenshots/screenshots-dashboard.png +0 -0
- package/assets/screenshots/screenshots-en.png +0 -0
- package/assets/screenshots/screenshots-git-reviewer.png +0 -0
- package/assets/screenshots/screenshots-import.png +0 -0
- package/assets/screenshots/screenshots-worktree-tool.png +0 -0
- package/assets/screenshots/screenshots-zh.png +0 -0
- package/cordis.patch.yml +6 -19
- package/lib/client/WorktreeSurface.d.ts.map +1 -1
- package/lib/client/WorktreeSurface.js +41 -13
- package/lib/client/WorktreeSurface.js.map +1 -1
- package/lib/client/branch/GitBranchSelector.d.ts +23 -0
- package/lib/client/branch/GitBranchSelector.d.ts.map +1 -0
- package/lib/client/branch/GitBranchSelector.js +142 -0
- package/lib/client/branch/GitBranchSelector.js.map +1 -0
- package/lib/client/command-activity.d.ts +11 -0
- package/lib/client/command-activity.d.ts.map +1 -0
- package/lib/client/command-activity.js +71 -0
- package/lib/client/command-activity.js.map +1 -0
- package/lib/client/context/worktree-context-store.d.ts.map +1 -1
- package/lib/client/context/worktree-context-store.js +1 -0
- package/lib/client/context/worktree-context-store.js.map +1 -1
- package/lib/client/context/worktree-context.d.ts +3 -2
- package/lib/client/context/worktree-context.d.ts.map +1 -1
- package/lib/client/context/worktree-context.js +5 -3
- package/lib/client/context/worktree-context.js.map +1 -1
- package/lib/client/dashboard/DashboardRequest.d.ts +2 -1
- package/lib/client/dashboard/DashboardRequest.d.ts.map +1 -1
- package/lib/client/dashboard/DashboardRequest.js +3 -3
- package/lib/client/dashboard/DashboardRequest.js.map +1 -1
- package/lib/client/dashboard/WorktreeDashboard.d.ts +6 -2
- package/lib/client/dashboard/WorktreeDashboard.d.ts.map +1 -1
- package/lib/client/dashboard/WorktreeDashboard.js +111 -89
- package/lib/client/dashboard/WorktreeDashboard.js.map +1 -1
- package/lib/client/dashboard/WorktreeInstructions.d.ts +2 -1
- package/lib/client/dashboard/WorktreeInstructions.d.ts.map +1 -1
- package/lib/client/dashboard/WorktreeInstructions.js +27 -8
- package/lib/client/dashboard/WorktreeInstructions.js.map +1 -1
- package/lib/client/dashboard/dashboard-overlay.d.ts.map +1 -1
- package/lib/client/dashboard/dashboard-overlay.js +38 -52
- package/lib/client/dashboard/dashboard-overlay.js.map +1 -1
- package/lib/client/dashboard/dashboard-selection.d.ts +4 -2
- package/lib/client/dashboard/dashboard-selection.d.ts.map +1 -1
- package/lib/client/dashboard/dashboard-selection.js +6 -4
- package/lib/client/dashboard/dashboard-selection.js.map +1 -1
- package/lib/client/dashboard/git/GitChangedFiles.d.ts +2 -1
- package/lib/client/dashboard/git/GitChangedFiles.d.ts.map +1 -1
- package/lib/client/dashboard/git/GitChangedFiles.js +8 -6
- package/lib/client/dashboard/git/GitChangedFiles.js.map +1 -1
- package/lib/client/dashboard/git/GitCommitList.d.ts +6 -1
- package/lib/client/dashboard/git/GitCommitList.d.ts.map +1 -1
- package/lib/client/dashboard/git/GitCommitList.js +34 -29
- package/lib/client/dashboard/git/GitCommitList.js.map +1 -1
- package/lib/client/dashboard/git/GitCommitStats.d.ts +8 -0
- package/lib/client/dashboard/git/GitCommitStats.d.ts.map +1 -0
- package/lib/client/dashboard/git/GitCommitStats.js +7 -0
- package/lib/client/dashboard/git/GitCommitStats.js.map +1 -0
- package/lib/client/dashboard/git/WorktreeGitOverview.d.ts.map +1 -1
- package/lib/client/dashboard/git/WorktreeGitOverview.js +2 -1
- package/lib/client/dashboard/git/WorktreeGitOverview.js.map +1 -1
- package/lib/client/dashboard/git/WorktreeGitPanel.d.ts +3 -2
- package/lib/client/dashboard/git/WorktreeGitPanel.d.ts.map +1 -1
- package/lib/client/dashboard/git/WorktreeGitPanel.js +79 -14
- package/lib/client/dashboard/git/WorktreeGitPanel.js.map +1 -1
- package/lib/client/dashboard/git/file-address.d.ts +5 -1
- package/lib/client/dashboard/git/file-address.d.ts.map +1 -1
- package/lib/client/dashboard/git/file-address.js +49 -11
- package/lib/client/dashboard/git/file-address.js.map +1 -1
- package/lib/client/dashboard/git/git-facts.js +1 -1
- package/lib/client/dashboard/git/git-facts.js.map +1 -1
- package/lib/client/dashboard/git/useWorktreeGitState.d.ts +7 -2
- package/lib/client/dashboard/git/useWorktreeGitState.d.ts.map +1 -1
- package/lib/client/dashboard/git/useWorktreeGitState.js +88 -22
- package/lib/client/dashboard/git/useWorktreeGitState.js.map +1 -1
- package/lib/client/dsh-icons.d.ts +4 -0
- package/lib/client/dsh-icons.d.ts.map +1 -1
- package/lib/client/dsh-icons.js +5 -1
- package/lib/client/dsh-icons.js.map +1 -1
- package/lib/client/dsh-slot-contract.d.ts +9 -1
- package/lib/client/dsh-slot-contract.d.ts.map +1 -1
- package/lib/client/entry.d.ts.map +1 -1
- package/lib/client/entry.js +39 -2
- package/lib/client/entry.js.map +1 -1
- package/lib/client/layout/app-frame.d.ts +12 -0
- package/lib/client/layout/app-frame.d.ts.map +1 -0
- package/lib/client/layout/app-frame.js +82 -0
- package/lib/client/layout/app-frame.js.map +1 -0
- package/lib/client/locales.d.ts +184 -2
- package/lib/client/locales.d.ts.map +1 -1
- package/lib/client/locales.js +250 -68
- package/lib/client/locales.js.map +1 -1
- package/lib/client/overlay/overlay-bounds.d.ts.map +1 -1
- package/lib/client/overlay/overlay-bounds.js +8 -3
- package/lib/client/overlay/overlay-bounds.js.map +1 -1
- package/lib/client/overlay/sidebar-overlay-geometry.d.ts +3 -1
- package/lib/client/overlay/sidebar-overlay-geometry.d.ts.map +1 -1
- package/lib/client/overlay/sidebar-overlay-geometry.js +94 -34
- package/lib/client/overlay/sidebar-overlay-geometry.js.map +1 -1
- package/lib/client/restart-notice.d.ts +10 -3
- package/lib/client/restart-notice.d.ts.map +1 -1
- package/lib/client/restart-notice.js +44 -11
- package/lib/client/restart-notice.js.map +1 -1
- package/lib/client/select/SearchableSingleSelect.d.ts +44 -0
- package/lib/client/select/SearchableSingleSelect.d.ts.map +1 -0
- package/lib/client/select/SearchableSingleSelect.js +180 -0
- package/lib/client/select/SearchableSingleSelect.js.map +1 -0
- package/lib/client/select/WorktreeSelector.d.ts +14 -0
- package/lib/client/select/WorktreeSelector.d.ts.map +1 -0
- package/lib/client/select/WorktreeSelector.js +11 -0
- package/lib/client/select/WorktreeSelector.js.map +1 -0
- package/lib/client/session/session-view.d.ts +16 -2
- package/lib/client/session/session-view.d.ts.map +1 -1
- package/lib/client/session/session-view.js +24 -10
- package/lib/client/session/session-view.js.map +1 -1
- package/lib/client/session/worktree-session.d.ts +1 -0
- package/lib/client/session/worktree-session.d.ts.map +1 -1
- package/lib/client/session/worktree-session.js +3 -1
- package/lib/client/session/worktree-session.js.map +1 -1
- package/lib/client/settings/ToolSettings.d.ts +9 -0
- package/lib/client/settings/ToolSettings.d.ts.map +1 -0
- package/lib/client/settings/ToolSettings.js +77 -0
- package/lib/client/settings/ToolSettings.js.map +1 -0
- package/lib/client/settings/WorktreeSettings.d.ts +8 -0
- package/lib/client/settings/WorktreeSettings.d.ts.map +1 -0
- package/lib/client/settings/WorktreeSettings.js +46 -0
- package/lib/client/settings/WorktreeSettings.js.map +1 -0
- package/lib/client/settings/WorktreeSettingsNavIcon.d.ts +6 -0
- package/lib/client/settings/WorktreeSettingsNavIcon.d.ts.map +1 -0
- package/lib/client/settings/WorktreeSettingsNavIcon.js +51 -0
- package/lib/client/settings/WorktreeSettingsNavIcon.js.map +1 -0
- package/lib/client/settings/diagnostics.d.ts +24 -0
- package/lib/client/settings/diagnostics.d.ts.map +1 -0
- package/lib/client/settings/diagnostics.js +63 -0
- package/lib/client/settings/diagnostics.js.map +1 -0
- package/lib/client/settings/settings-navigation.d.ts +7 -0
- package/lib/client/settings/settings-navigation.d.ts.map +1 -0
- package/lib/client/settings/settings-navigation.js +12 -0
- package/lib/client/settings/settings-navigation.js.map +1 -0
- package/lib/client/surface/actions/useLifecycleActions.d.ts +2 -1
- package/lib/client/surface/actions/useLifecycleActions.d.ts.map +1 -1
- package/lib/client/surface/actions/useLifecycleActions.js +15 -6
- package/lib/client/surface/actions/useLifecycleActions.js.map +1 -1
- package/lib/client/surface/actions/useSessionActions.d.ts.map +1 -1
- package/lib/client/surface/actions/useSessionActions.js +6 -6
- package/lib/client/surface/actions/useSessionActions.js.map +1 -1
- package/lib/client/surface/actions/useWorktreeRegistration.d.ts +1 -1
- package/lib/client/surface/actions/useWorktreeRegistration.d.ts.map +1 -1
- package/lib/client/surface/actions/useWorktreeRegistration.js +36 -13
- package/lib/client/surface/actions/useWorktreeRegistration.js.map +1 -1
- package/lib/client/surface/components/NotificationToasts.d.ts +19 -3
- package/lib/client/surface/components/NotificationToasts.d.ts.map +1 -1
- package/lib/client/surface/components/NotificationToasts.js +73 -7
- package/lib/client/surface/components/NotificationToasts.js.map +1 -1
- package/lib/client/surface/components/OverlayScrollbar.d.ts +6 -0
- package/lib/client/surface/components/OverlayScrollbar.d.ts.map +1 -0
- package/lib/client/surface/components/OverlayScrollbar.js +84 -0
- package/lib/client/surface/components/OverlayScrollbar.js.map +1 -0
- package/lib/client/surface/components/RegistrationDialog.d.ts +3 -3
- package/lib/client/surface/components/RegistrationDialog.d.ts.map +1 -1
- package/lib/client/surface/components/RegistrationDialog.js +70 -5
- package/lib/client/surface/components/RegistrationDialog.js.map +1 -1
- package/lib/client/surface/components/RestartToast.d.ts.map +1 -1
- package/lib/client/surface/components/RestartToast.js +4 -3
- package/lib/client/surface/components/RestartToast.js.map +1 -1
- package/lib/client/surface/components/SurfaceContent.d.ts.map +1 -1
- package/lib/client/surface/components/SurfaceContent.js +110 -39
- package/lib/client/surface/components/SurfaceContent.js.map +1 -1
- package/lib/client/surface/components/WorkspaceTree.d.ts.map +1 -1
- package/lib/client/surface/components/WorkspaceTree.js +13 -9
- package/lib/client/surface/components/WorkspaceTree.js.map +1 -1
- package/lib/client/surface/components/dialogs.d.ts +1 -1
- package/lib/client/surface/components/dialogs.d.ts.map +1 -1
- package/lib/client/surface/components/dialogs.js +34 -21
- package/lib/client/surface/components/dialogs.js.map +1 -1
- package/lib/client/surface/components/rows.d.ts +1 -1
- package/lib/client/surface/components/rows.d.ts.map +1 -1
- package/lib/client/surface/components/rows.js +15 -97
- package/lib/client/surface/components/rows.js.map +1 -1
- package/lib/client/surface/notification-queue.d.ts +15 -0
- package/lib/client/surface/notification-queue.d.ts.map +1 -1
- package/lib/client/surface/notification-queue.js +13 -2
- package/lib/client/surface/notification-queue.js.map +1 -1
- package/lib/client/surface/state/useRegistrationState.d.ts +6 -1
- package/lib/client/surface/state/useRegistrationState.d.ts.map +1 -1
- package/lib/client/surface/state/useRegistrationState.js +7 -0
- package/lib/client/surface/state/useRegistrationState.js.map +1 -1
- package/lib/client/surface/state/useSurfaceRefresh.d.ts +1 -1
- package/lib/client/surface/state/useSurfaceRefresh.d.ts.map +1 -1
- package/lib/client/surface/state/useSurfaceRefresh.js +13 -1
- package/lib/client/surface/state/useSurfaceRefresh.js.map +1 -1
- package/lib/client/surface/state/useSurfaceSources.d.ts +1 -1
- package/lib/client/surface/state/useSurfaceSources.d.ts.map +1 -1
- package/lib/client/surface/state/useSurfaceSources.js +4 -2
- package/lib/client/surface/state/useSurfaceSources.js.map +1 -1
- package/lib/client/surface/state/useTitleMarquee.d.ts +7 -0
- package/lib/client/surface/state/useTitleMarquee.d.ts.map +1 -0
- package/lib/client/surface/state/useTitleMarquee.js +60 -0
- package/lib/client/surface/state/useTitleMarquee.js.map +1 -0
- package/lib/client/surface/types.d.ts +12 -1
- package/lib/client/surface/types.d.ts.map +1 -1
- package/lib/client/view/worktree-error-copy.d.ts.map +1 -1
- package/lib/client/view/worktree-error-copy.js +73 -14
- package/lib/client/view/worktree-error-copy.js.map +1 -1
- package/lib/client/view/worktree-view-errors.d.ts.map +1 -1
- package/lib/client/view/worktree-view-errors.js +13 -5
- package/lib/client/view/worktree-view-errors.js.map +1 -1
- package/lib/client/view/worktree-view-read.d.ts +4 -2
- package/lib/client/view/worktree-view-read.d.ts.map +1 -1
- package/lib/client/view/worktree-view-read.js +34 -17
- package/lib/client/view/worktree-view-read.js.map +1 -1
- package/lib/client/worktree-connection.d.ts +9 -2
- package/lib/client/worktree-connection.d.ts.map +1 -1
- package/lib/client/worktree-connection.js +24 -1
- package/lib/client/worktree-connection.js.map +1 -1
- package/lib/client/worktree-tool-changes.d.ts +13 -0
- package/lib/client/worktree-tool-changes.d.ts.map +1 -0
- package/lib/client/worktree-tool-changes.js +64 -0
- package/lib/client/worktree-tool-changes.js.map +1 -0
- package/lib/client.js +3503 -1310
- package/lib/client.js.map +1 -1
- package/lib/contract/index.contract.js +15 -0
- package/lib/contract/index.contract.js.map +1 -1
- package/lib/contract/index.d.ts +79 -12
- package/lib/contract/index.d.ts.map +1 -1
- package/lib/contract/index.js +12 -0
- package/lib/contract/index.js.map +1 -1
- package/lib/contract/tool-settings.d.ts +28 -0
- package/lib/contract/tool-settings.d.ts.map +1 -0
- package/lib/contract/tool-settings.js +10 -0
- package/lib/contract/tool-settings.js.map +1 -0
- package/lib/contract/worktree-tool-changes.d.ts +10 -0
- package/lib/contract/worktree-tool-changes.d.ts.map +1 -0
- package/lib/contract/worktree-tool-changes.js +2 -0
- package/lib/contract/worktree-tool-changes.js.map +1 -0
- package/lib/host/permission-preset-append.d.ts +15 -0
- package/lib/host/permission-preset-append.d.ts.map +1 -0
- package/lib/host/permission-preset-append.js +63 -0
- package/lib/host/permission-preset-append.js.map +1 -0
- package/lib/host/remote.d.ts.map +1 -1
- package/lib/host/remote.js +7 -0
- package/lib/host/remote.js.map +1 -1
- package/lib/host/service.d.ts +30 -6
- package/lib/host/service.d.ts.map +1 -1
- package/lib/host/service.js +85 -11
- package/lib/host/service.js.map +1 -1
- package/lib/host/tool-settings.d.ts +14 -0
- package/lib/host/tool-settings.d.ts.map +1 -0
- package/lib/host/tool-settings.js +98 -0
- package/lib/host/tool-settings.js.map +1 -0
- package/lib/host/worktree-permission-manager.d.ts.map +1 -1
- package/lib/host/worktree-permission-manager.js +2 -4
- package/lib/host/worktree-permission-manager.js.map +1 -1
- package/lib/host/worktree-tool-changes.d.ts +12 -0
- package/lib/host/worktree-tool-changes.d.ts.map +1 -0
- package/lib/host/worktree-tool-changes.js +60 -0
- package/lib/host/worktree-tool-changes.js.map +1 -0
- package/lib/manage/manager-git-history.d.ts +5 -7
- package/lib/manage/manager-git-history.d.ts.map +1 -1
- package/lib/manage/manager-git-history.js +185 -91
- package/lib/manage/manager-git-history.js.map +1 -1
- package/lib/manage/manager-git-paths.d.ts +7 -0
- package/lib/manage/manager-git-paths.d.ts.map +1 -0
- package/lib/manage/manager-git-paths.js +62 -0
- package/lib/manage/manager-git-paths.js.map +1 -0
- package/lib/manage/manager-sessions.d.ts +5 -0
- package/lib/manage/manager-sessions.d.ts.map +1 -1
- package/lib/manage/manager-sessions.js +34 -11
- package/lib/manage/manager-sessions.js.map +1 -1
- package/lib/manage/manager-support.d.ts +3 -1
- package/lib/manage/manager-support.d.ts.map +1 -1
- package/lib/manage/manager-support.js +17 -0
- package/lib/manage/manager-support.js.map +1 -1
- package/lib/manage/manager-worktree-lifecycle.d.ts.map +1 -1
- package/lib/manage/manager-worktree-lifecycle.js +5 -4
- package/lib/manage/manager-worktree-lifecycle.js.map +1 -1
- package/lib/manage/manager-worktrees.d.ts +10 -1
- package/lib/manage/manager-worktrees.d.ts.map +1 -1
- package/lib/manage/manager-worktrees.js +141 -34
- package/lib/manage/manager-worktrees.js.map +1 -1
- package/lib/manage/manager.d.ts +22 -5
- package/lib/manage/manager.d.ts.map +1 -1
- package/lib/manage/manager.js +76 -4
- package/lib/manage/manager.js.map +1 -1
- package/lib/manage/types.d.ts +10 -1
- package/lib/manage/types.d.ts.map +1 -1
- package/lib/provider/generated-name.d.ts.map +1 -1
- package/lib/provider/generated-name.js +5 -4
- package/lib/provider/generated-name.js.map +1 -1
- package/lib/provider/git/adapter.d.ts +13 -12
- package/lib/provider/git/adapter.d.ts.map +1 -1
- package/lib/provider/git/adapter.js +157 -31
- package/lib/provider/git/adapter.js.map +1 -1
- package/lib/provider/git/branch-name.d.ts +5 -0
- package/lib/provider/git/branch-name.d.ts.map +1 -0
- package/lib/provider/git/branch-name.js +16 -0
- package/lib/provider/git/branch-name.js.map +1 -0
- package/lib/provider/git/branches.d.ts +11 -0
- package/lib/provider/git/branches.d.ts.map +1 -0
- package/lib/provider/git/branches.js +37 -0
- package/lib/provider/git/branches.js.map +1 -0
- package/lib/provider/mutation-token.d.ts +1 -1
- package/lib/provider/mutation-token.d.ts.map +1 -1
- package/lib/provider/mutation-token.js +1 -0
- package/lib/provider/mutation-token.js.map +1 -1
- package/lib/provider/sidecar/repository.d.ts.map +1 -1
- package/lib/provider/sidecar/repository.js +3 -1
- package/lib/provider/sidecar/repository.js.map +1 -1
- package/lib/provider/sidecar/sidecar-schema.d.ts.map +1 -1
- package/lib/provider/sidecar/sidecar-schema.js +26 -4
- package/lib/provider/sidecar/sidecar-schema.js.map +1 -1
- package/lib/provider/transaction/operations/adopt-branch.d.ts.map +1 -1
- package/lib/provider/transaction/operations/adopt-branch.js +6 -5
- package/lib/provider/transaction/operations/adopt-branch.js.map +1 -1
- package/lib/provider/transaction/operations/clean.d.ts.map +1 -1
- package/lib/provider/transaction/operations/clean.js +20 -19
- package/lib/provider/transaction/operations/clean.js.map +1 -1
- package/lib/provider/transaction/operations/create.d.ts +1 -1
- package/lib/provider/transaction/operations/create.d.ts.map +1 -1
- package/lib/provider/transaction/operations/create.js +39 -17
- package/lib/provider/transaction/operations/create.js.map +1 -1
- package/lib/provider/transaction/operations/import.d.ts.map +1 -1
- package/lib/provider/transaction/operations/import.js +7 -1
- package/lib/provider/transaction/operations/import.js.map +1 -1
- package/lib/provider/transaction/operations/remove.d.ts.map +1 -1
- package/lib/provider/transaction/operations/remove.js +20 -19
- package/lib/provider/transaction/operations/remove.js.map +1 -1
- package/lib/provider/transaction/recovery/failure-recovery.d.ts.map +1 -1
- package/lib/provider/transaction/recovery/failure-recovery.js +22 -20
- package/lib/provider/transaction/recovery/failure-recovery.js.map +1 -1
- package/lib/provider/transaction/recovery/recover.d.ts.map +1 -1
- package/lib/provider/transaction/recovery/recover.js +11 -4
- package/lib/provider/transaction/recovery/recover.js.map +1 -1
- package/lib/provider/transaction/support/inspection.d.ts.map +1 -1
- package/lib/provider/transaction/support/inspection.js +3 -2
- package/lib/provider/transaction/support/inspection.js.map +1 -1
- package/lib/provider/transaction/support/journal.d.ts.map +1 -1
- package/lib/provider/transaction/support/journal.js +9 -5
- package/lib/provider/transaction/support/journal.js.map +1 -1
- package/lib/provider/transaction/support/path-safety.d.ts.map +1 -1
- package/lib/provider/transaction/support/path-safety.js +4 -3
- package/lib/provider/transaction/support/path-safety.js.map +1 -1
- package/lib/provider/transaction/types.d.ts +2 -1
- package/lib/provider/transaction/types.d.ts.map +1 -1
- package/lib/provider/types.d.ts +27 -5
- package/lib/provider/types.d.ts.map +1 -1
- package/lib/provider/types.js +1 -1
- package/lib/provider/types.js.map +1 -1
- package/lib/provider/worktree-path.d.ts +10 -0
- package/lib/provider/worktree-path.d.ts.map +1 -0
- package/lib/provider/worktree-path.js +47 -0
- package/lib/provider/worktree-path.js.map +1 -0
- package/lib/tool/context.d.ts +14 -0
- package/lib/tool/context.d.ts.map +1 -0
- package/lib/tool/context.js +95 -0
- package/lib/tool/context.js.map +1 -0
- package/lib/tool/delegation.d.ts +41 -0
- package/lib/tool/delegation.d.ts.map +1 -0
- package/lib/tool/delegation.js +196 -0
- package/lib/tool/delegation.js.map +1 -0
- package/lib/tool/errors.d.ts +3 -0
- package/lib/tool/errors.d.ts.map +1 -0
- package/lib/tool/errors.js +63 -0
- package/lib/tool/errors.js.map +1 -0
- package/lib/tool/guidance.d.ts +5 -0
- package/lib/tool/guidance.d.ts.map +1 -0
- package/lib/tool/guidance.js +48 -0
- package/lib/tool/guidance.js.map +1 -0
- package/lib/tool/history.d.ts +27 -0
- package/lib/tool/history.d.ts.map +1 -0
- package/lib/tool/history.js +157 -0
- package/lib/tool/history.js.map +1 -0
- package/lib/tool/index.d.ts +8 -0
- package/lib/tool/index.d.ts.map +1 -0
- package/lib/tool/index.js +296 -0
- package/lib/tool/index.js.map +1 -0
- package/lib/tool/inputs.d.ts +12 -0
- package/lib/tool/inputs.d.ts.map +1 -0
- package/lib/tool/inputs.js +24 -0
- package/lib/tool/inputs.js.map +1 -0
- package/lib/tool/list-models.d.ts +3 -0
- package/lib/tool/list-models.d.ts.map +1 -0
- package/lib/tool/list-models.js +38 -0
- package/lib/tool/list-models.js.map +1 -0
- package/lib/tool/list-sessions.d.ts +3 -0
- package/lib/tool/list-sessions.d.ts.map +1 -0
- package/lib/tool/list-sessions.js +70 -0
- package/lib/tool/list-sessions.js.map +1 -0
- package/lib/tool/list-worktrees.d.ts +3 -0
- package/lib/tool/list-worktrees.d.ts.map +1 -0
- package/lib/tool/list-worktrees.js +46 -0
- package/lib/tool/list-worktrees.js.map +1 -0
- package/lib/tool/native-session.d.ts +74 -0
- package/lib/tool/native-session.d.ts.map +1 -0
- package/lib/tool/native-session.js +248 -0
- package/lib/tool/native-session.js.map +1 -0
- package/lib/tool/new-worktree.d.ts +3 -0
- package/lib/tool/new-worktree.d.ts.map +1 -0
- package/lib/tool/new-worktree.js +81 -0
- package/lib/tool/new-worktree.js.map +1 -0
- package/lib/tool/outputs.d.ts +50 -0
- package/lib/tool/outputs.d.ts.map +1 -0
- package/lib/tool/outputs.js +65 -0
- package/lib/tool/outputs.js.map +1 -0
- package/lib/tool/report-result.d.ts +3 -0
- package/lib/tool/report-result.d.ts.map +1 -0
- package/lib/tool/report-result.js +83 -0
- package/lib/tool/report-result.js.map +1 -0
- package/lib/tool/schema.d.ts +7 -0
- package/lib/tool/schema.d.ts.map +1 -0
- package/lib/tool/schema.js +92 -0
- package/lib/tool/schema.js.map +1 -0
- package/lib/tool/send-message.d.ts +3 -0
- package/lib/tool/send-message.d.ts.map +1 -0
- package/lib/tool/send-message.js +64 -0
- package/lib/tool/send-message.js.map +1 -0
- package/lib/tool/span-worktree.d.ts +3 -0
- package/lib/tool/span-worktree.d.ts.map +1 -0
- package/lib/tool/span-worktree.js +114 -0
- package/lib/tool/span-worktree.js.map +1 -0
- package/lib/tool/types.d.ts +54 -0
- package/lib/tool/types.d.ts.map +1 -0
- package/lib/tool/types.js +2 -0
- package/lib/tool/types.js.map +1 -0
- package/lib/typert.host.js +387 -46
- package/lib/typert.remote-client.d.ts +17 -5
- package/lib/typert.remote-client.d.ts.map +1 -1
- package/lib/typert.remote-client.js +387 -46
- 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
|
-
|
|
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
|
|
89
|
-
throw providerError('WORKTREE_NOT_FOUND', `Worktree directory is unavailable: ${record
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 (!
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
182
|
+
const selected = await resolveBranchCommit(context, resolved, baseBranch, {
|
|
175
183
|
allowUnavailable: true,
|
|
176
184
|
});
|
|
177
|
-
if (
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
798
|
+
return selectedAggregateFileDiff(context, gitWorktreeRoot(resolved.record), resolved.record.worktreeId, authorized.selection, authorized.commits, requestedPath);
|
|
737
799
|
}
|
|
738
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|