@cerbur/clutch-dsh-worktree 0.1.6 → 0.1.7

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 (116) hide show
  1. package/README.md +107 -15
  2. package/README.zh.md +86 -10
  3. package/cordis.patch.yml +21 -0
  4. package/lib/client/WorktreeContext.d.ts.map +1 -1
  5. package/lib/client/WorktreeContext.js +2 -2
  6. package/lib/client/WorktreeContext.js.map +1 -1
  7. package/lib/client/WorktreeSurface.d.ts +2 -2
  8. package/lib/client/WorktreeSurface.d.ts.map +1 -1
  9. package/lib/client/WorktreeSurface.js +270 -65
  10. package/lib/client/WorktreeSurface.js.map +1 -1
  11. package/lib/client/entry.d.ts.map +1 -1
  12. package/lib/client/entry.js +84 -2
  13. package/lib/client/entry.js.map +1 -1
  14. package/lib/client/index.d.ts +3 -0
  15. package/lib/client/index.d.ts.map +1 -1
  16. package/lib/client/index.js +2 -0
  17. package/lib/client/index.js.map +1 -1
  18. package/lib/client/locales.d.ts +58 -0
  19. package/lib/client/locales.d.ts.map +1 -1
  20. package/lib/client/locales.js +58 -0
  21. package/lib/client/locales.js.map +1 -1
  22. package/lib/client/session-view.d.ts +34 -0
  23. package/lib/client/session-view.d.ts.map +1 -1
  24. package/lib/client/session-view.js +119 -1
  25. package/lib/client/session-view.js.map +1 -1
  26. package/lib/client/worktree-connection.d.ts +4 -2
  27. package/lib/client/worktree-connection.d.ts.map +1 -1
  28. package/lib/client/worktree-connection.js +4 -0
  29. package/lib/client/worktree-connection.js.map +1 -1
  30. package/lib/client/worktree-error-copy.d.ts +2 -0
  31. package/lib/client/worktree-error-copy.d.ts.map +1 -1
  32. package/lib/client/worktree-error-copy.js +16 -0
  33. package/lib/client/worktree-error-copy.js.map +1 -1
  34. package/lib/client/worktree-permission-icon.d.ts +7 -0
  35. package/lib/client/worktree-permission-icon.d.ts.map +1 -0
  36. package/lib/client/worktree-permission-icon.js +119 -0
  37. package/lib/client/worktree-permission-icon.js.map +1 -0
  38. package/lib/client/worktree-permission.d.ts +21 -0
  39. package/lib/client/worktree-permission.d.ts.map +1 -0
  40. package/lib/client/worktree-permission.js +70 -0
  41. package/lib/client/worktree-permission.js.map +1 -0
  42. package/lib/client/worktree-session-fork.d.ts +65 -0
  43. package/lib/client/worktree-session-fork.d.ts.map +1 -0
  44. package/lib/client/worktree-session-fork.js +174 -0
  45. package/lib/client/worktree-session-fork.js.map +1 -0
  46. package/lib/client/worktree-session-order.d.ts +36 -0
  47. package/lib/client/worktree-session-order.d.ts.map +1 -0
  48. package/lib/client/worktree-session-order.js +215 -0
  49. package/lib/client/worktree-session-order.js.map +1 -0
  50. package/lib/client/worktree-session.d.ts +34 -1
  51. package/lib/client/worktree-session.d.ts.map +1 -1
  52. package/lib/client/worktree-session.js +98 -2
  53. package/lib/client/worktree-session.js.map +1 -1
  54. package/lib/client/worktree-surface-rows.d.ts +4 -4
  55. package/lib/client/worktree-surface-rows.d.ts.map +1 -1
  56. package/lib/client/worktree-surface-rows.js +132 -47
  57. package/lib/client/worktree-surface-rows.js.map +1 -1
  58. package/lib/client/worktree-surface-selectors.d.ts +2 -0
  59. package/lib/client/worktree-surface-selectors.d.ts.map +1 -1
  60. package/lib/client/worktree-surface-selectors.js +8 -0
  61. package/lib/client/worktree-surface-selectors.js.map +1 -1
  62. package/lib/client/worktree-surface-types.d.ts +46 -3
  63. package/lib/client/worktree-surface-types.d.ts.map +1 -1
  64. package/lib/client/worktree-view-actions.d.ts +8 -3
  65. package/lib/client/worktree-view-actions.d.ts.map +1 -1
  66. package/lib/client/worktree-view-actions.js +28 -2
  67. package/lib/client/worktree-view-actions.js.map +1 -1
  68. package/lib/client/worktree-view-errors.d.ts +10 -0
  69. package/lib/client/worktree-view-errors.d.ts.map +1 -1
  70. package/lib/client/worktree-view-errors.js +22 -1
  71. package/lib/client/worktree-view-errors.js.map +1 -1
  72. package/lib/client.js +1473 -201
  73. package/lib/client.js.map +1 -1
  74. package/lib/contract/index.contract.js +2 -0
  75. package/lib/contract/index.contract.js.map +1 -1
  76. package/lib/contract/index.d.ts +6 -2
  77. package/lib/contract/index.d.ts.map +1 -1
  78. package/lib/contract/index.js +4 -0
  79. package/lib/contract/index.js.map +1 -1
  80. package/lib/contract/worktree-permission.d.ts +73 -0
  81. package/lib/contract/worktree-permission.d.ts.map +1 -0
  82. package/lib/contract/worktree-permission.js +32 -0
  83. package/lib/contract/worktree-permission.js.map +1 -0
  84. package/lib/host/index.d.ts +4 -0
  85. package/lib/host/index.d.ts.map +1 -1
  86. package/lib/host/index.js +2 -0
  87. package/lib/host/index.js.map +1 -1
  88. package/lib/host/remote.d.ts +2 -2
  89. package/lib/host/remote.d.ts.map +1 -1
  90. package/lib/host/remote.js +7 -1
  91. package/lib/host/remote.js.map +1 -1
  92. package/lib/host/service.d.ts +3 -1
  93. package/lib/host/service.d.ts.map +1 -1
  94. package/lib/host/service.js +36 -2
  95. package/lib/host/service.js.map +1 -1
  96. package/lib/host/worktree-permission-manager.d.ts +14 -0
  97. package/lib/host/worktree-permission-manager.d.ts.map +1 -0
  98. package/lib/host/worktree-permission-manager.js +111 -0
  99. package/lib/host/worktree-permission-manager.js.map +1 -0
  100. package/lib/host/worktree-permission.d.ts +38 -0
  101. package/lib/host/worktree-permission.d.ts.map +1 -0
  102. package/lib/host/worktree-permission.js +156 -0
  103. package/lib/host/worktree-permission.js.map +1 -0
  104. package/lib/index.d.ts +4 -3
  105. package/lib/index.d.ts.map +1 -1
  106. package/lib/index.js +2 -1
  107. package/lib/index.js.map +1 -1
  108. package/lib/manage/worktree-permission.d.ts +3 -0
  109. package/lib/manage/worktree-permission.d.ts.map +1 -0
  110. package/lib/manage/worktree-permission.js +3 -0
  111. package/lib/manage/worktree-permission.js.map +1 -0
  112. package/lib/typert.host.js +126 -27
  113. package/lib/typert.remote-client.d.ts +5 -1
  114. package/lib/typert.remote-client.d.ts.map +1 -1
  115. package/lib/typert.remote-client.js +126 -27
  116. package/package.json +1 -1
@@ -1,18 +1,19 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, } from 'react';
3
- import { IconBranchOutline16, IconCloseOutline16, IconPlusOutline16, IconSearchOutline16, } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import { IconBranchOutline16, IconCloseOutline16, IconProjectAddOutline16, IconSearchOutline16, RiskConfirmation, } from '@deepseek-ai/dsh-client-ui-primitives';
4
4
  import { openWorktreeSession } from './navigation.js';
5
5
  import { useSidebarOverlayGeometry } from './sidebar-overlay-geometry.js';
6
6
  import { isMainExpanded, isWorkspaceExpanded, isWorktreeExpanded, } from './worktree-expand-state.js';
7
7
  import { effectiveViewMode, unboundSessionIds, workspaceSessionIds } from './view-mode.js';
8
- import { formatWorktreeViewError } from './worktree-error-copy.js';
9
- import { filterVisibleSessionIds, sessionMatchesQuery, } from './session-view.js';
8
+ import { formatWorktreePermissionNotice, formatWorktreeViewError, } from './worktree-error-copy.js';
9
+ import { deriveSessionPresentationIndex, filterVisibleSessionIds, hasOngoingSession, sessionMatchesQuery, } from './session-view.js';
10
+ import { nextSessionOrderAccount, reorderSessionIds, } from './worktree-session-order.js';
10
11
  import { retryWorktreeSessionBinding } from './worktree-session.js';
11
12
  import { WorktreeCreateDialog, WorktreeRemovalDialog, WorktreeSessionRenameDialog, WorktreeWorkspaceDeleteDialog, WorktreeWorkspaceRenameDialog, } from './worktree-surface-dialogs.js';
12
- import { bindingIdsFor, clearSessionGroupExpansion, includesText, isCompleteWorktreeWorkspaceSnapshot, currentSessionRevealKeys, resolveCurrentSessionLocation, workspaceMatches, } from './worktree-surface-selectors.js';
13
+ import { bindingIdsFor, clearSessionGroupExpansion, includesText, isCompleteWorktreeWorkspaceSnapshot, currentSessionRevealKeys, isSessionGroupAutoExpanded, resolveCurrentSessionLocation, workspaceMatches, } from './worktree-surface-selectors.js';
13
14
  import { scrollCurrentSessionIntoView } from './worktree-session-position.js';
14
15
  import { WorktreeGroupRow, WorktreeSessionGroup, WorktreeWorkspaceRow, } from './worktree-surface-rows.js';
15
- import { executeWorktreeAction, createDefaultWorktreeName, createWorktreeModalViewLoader, createWorktreeRefreshGuard, filterArchivedSessionIds, loadWorktreeViews, mergeWorktreeView, reconcileBaseBranchSelection, resolveWorktreeMove, selectDefaultBaseBranch, stableWorkspaceIds, toRetryableWorktreeOrderError, toWorktreeViewError, WorktreeSessionBindingError, } from './worktree-view.js';
16
+ import { executeWorktreeAction, createDefaultWorktreeName, createNumberedWorktreeName, createWorktreeModalViewLoader, createWorktreeRefreshGuard, filterArchivedSessionIds, loadWorktreeViews, mergeWorktreeView, reconcileBaseBranchSelection, resolveWorktreeMove, selectDefaultBaseBranch, stableWorkspaceIds, toRetryableWorktreeOrderError, toWorktreeViewError, WorktreeSessionBindingError, WorktreeSessionPermissionError, } from './worktree-view.js';
16
17
  import styles from './worktree.css';
17
18
  function toNativeWorktreeViewError(error) {
18
19
  const viewError = toWorktreeViewError(error);
@@ -21,6 +22,30 @@ function toNativeWorktreeViewError(error) {
21
22
  return { ...viewError, message: String(error) };
22
23
  }
23
24
  const EMPTY_READ_STATE = { status: 'idle', views: [] };
25
+ const EMPTY_PERMISSION_NOTICE = undefined;
26
+ const EMPTY_PERMISSION_NOTICE_SUBSCRIBE = () => () => { };
27
+ const EMPTY_PERMISSION_NOTICE_SNAPSHOT = () => EMPTY_PERMISSION_NOTICE;
28
+ const EMPTY_FULL_ACCESS_CONFIRMATION_SUBSCRIBE = () => () => { };
29
+ const EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT = () => undefined;
30
+ const EMPTY_FORK_RECOVERY_SNAPSHOT = { revision: 0, pending: [] };
31
+ const EMPTY_FORK_RECOVERY_STORE = {
32
+ getSnapshot: () => EMPTY_FORK_RECOVERY_SNAPSHOT,
33
+ subscribe: () => () => { },
34
+ };
35
+ function updatedAtById(sessionIds, sessions) {
36
+ return Object.fromEntries(sessionIds.map((sessionId) => [sessionId, sessions.byId[sessionId]?.updatedAt]));
37
+ }
38
+ function forkRecoveryError(recovery) {
39
+ const error = toNativeWorktreeViewError(recovery.error);
40
+ return {
41
+ ...error,
42
+ code: error.code === 'WORKTREE_VIEW_FAILED' ? 'SESSION_BINDING_FAILED' : error.code,
43
+ details: {
44
+ ...(error.details ?? {}),
45
+ sessionId: recovery.childSessionId,
46
+ },
47
+ };
48
+ }
24
49
  function useStableWorkspaceIds(workspaces) {
25
50
  const next = workspaces.map((workspace) => workspace.workspaceId);
26
51
  const previousRef = useRef([]);
@@ -33,15 +58,33 @@ function useStableWorkspaceIds(workspaces) {
33
58
  * Peer Worktree navigation surface. It keeps the original DSH Workspace mode
34
59
  * intact and renders a browser-local Workspace → Worktree → Session projection.
35
60
  */
36
- export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, expandState, manager, invalidateWorktreeContext, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, insertWorktreeBefore, renameSession, forkSession, archiveSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession, }) {
61
+ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, expandState, sessionOrder, manager, permission, confirmFullAccess, fullAccessConfirmation, onPermissionResult, onPermissionNotice, permissionNotice, invalidateWorktreeContext, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, insertWorktreeBefore, renameSession, forkSession, archiveSession, forkRecovery, retryForkSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession, }) {
37
62
  const preferredMode = useStore((state) => state.viewMode);
38
63
  const mode = effectiveViewMode(preferredMode, available && manager !== undefined);
39
64
  const sessions = useSessions((state) => state);
40
65
  const workspaces = useWorkspaces((state) => state);
66
+ const forkRecoveryStore = forkRecovery ?? EMPTY_FORK_RECOVERY_STORE;
67
+ const forkRecoverySnapshot = useSyncExternalStore(forkRecoveryStore.subscribe, forkRecoveryStore.getSnapshot, forkRecoveryStore.getSnapshot);
41
68
  const currentSessionId = sessions.current;
42
69
  const workspaceIds = useStableWorkspaceIds(workspaces.items);
43
70
  const [readState, setReadState] = useState(EMPTY_READ_STATE);
44
71
  const expandSnapshot = useSyncExternalStore(expandState.subscribe, expandState.getSnapshot, expandState.getSnapshot);
72
+ const permissionNoticeSnapshot = useSyncExternalStore(permissionNotice?.subscribe ?? EMPTY_PERMISSION_NOTICE_SUBSCRIBE, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT);
73
+ const fullAccessConfirmationSnapshot = useSyncExternalStore(fullAccessConfirmation?.subscribe ?? EMPTY_FULL_ACCESS_CONFIRMATION_SUBSCRIBE, fullAccessConfirmation?.getSnapshot ?? EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT, fullAccessConfirmation?.getSnapshot ?? EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT);
74
+ const fullAccessConfirmationKey = fullAccessConfirmationSnapshot === undefined
75
+ ? ''
76
+ : [
77
+ fullAccessConfirmationSnapshot.workspaceId,
78
+ fullAccessConfirmationSnapshot.worktreeId,
79
+ fullAccessConfirmationSnapshot.sessionId,
80
+ fullAccessConfirmationSnapshot.cwd,
81
+ ].join('\u0000');
82
+ const [fullAccessAcknowledged, setFullAccessAcknowledged] = useState(false);
83
+ useEffect(() => {
84
+ setFullAccessAcknowledged(false);
85
+ }, [fullAccessConfirmationKey]);
86
+ const sessionOrderSnapshot = useSyncExternalStore(sessionOrder.subscribe, sessionOrder.getSnapshot, sessionOrder.getSnapshot);
87
+ const sessionPresentations = useMemo(() => deriveSessionPresentationIndex(sessions), [sessions.byId]);
45
88
  const readStateRef = useRef(readState);
46
89
  readStateRef.current = readState;
47
90
  const [searchQuery, setSearchQuery] = useState('');
@@ -54,9 +97,13 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
54
97
  const [modalReadError, setModalReadError] = useState();
55
98
  const [modalReadLoading, setModalReadLoading] = useState(false);
56
99
  const [worktreeModalMode, setWorktreeModalMode] = useState('create');
57
- const [importCandidates, setImportCandidates] = useState({ status: 'idle', candidates: [] });
100
+ const [importCandidates, setImportCandidates] = useState({
101
+ status: 'idle',
102
+ candidates: [],
103
+ });
58
104
  const [selectedImportPath, setSelectedImportPath] = useState();
59
105
  const [openWorkspaceMenuId, setOpenWorkspaceMenuId] = useState();
106
+ const [openMainMenuId, setOpenMainMenuId] = useState();
60
107
  const [openWorktreeMenuId, setOpenWorktreeMenuId] = useState();
61
108
  const [worktreeRemoval, setWorktreeRemoval] = useState();
62
109
  const [selectedBranch, setSelectedBranch] = useState('');
@@ -64,6 +111,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
64
111
  const [pendingSessionBinding, setPendingSessionBinding] = useState();
65
112
  const [actionError, setActionError] = useState();
66
113
  const [actionPending, setActionPending] = useState(false);
114
+ const [forkRetryKey, setForkRetryKey] = useState();
67
115
  const [sessionRenameTarget, setSessionRenameTarget] = useState();
68
116
  const [sessionRenameDraft, setSessionRenameDraft] = useState('');
69
117
  const [sessionRenamePending, setSessionRenamePending] = useState(false);
@@ -83,6 +131,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
83
131
  const [worktreeDrag, setWorktreeDrag] = useState();
84
132
  const worktreeDropCommitted = useRef(false);
85
133
  const refreshGuard = useRef(createWorktreeRefreshGuard());
134
+ const forkRecoveryRevisionRef = useRef(forkRecoverySnapshot.revision);
86
135
  const modalReadLoader = useRef(createWorktreeModalViewLoader());
87
136
  const modalReadViewRef = useRef();
88
137
  const importCandidatesGuard = useRef(createWorktreeRefreshGuard());
@@ -119,9 +168,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
119
168
  throw error;
120
169
  setReadState({
121
170
  status: 'error',
122
- views: modalReadViewRef.current === undefined
123
- ? []
124
- : [modalReadViewRef.current],
171
+ views: modalReadViewRef.current === undefined ? [] : [modalReadViewRef.current],
125
172
  error: toWorktreeViewError(error),
126
173
  });
127
174
  });
@@ -164,6 +211,19 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
164
211
  setReadState(EMPTY_READ_STATE);
165
212
  }
166
213
  }, [mode, refresh]);
214
+ useEffect(() => {
215
+ if (forkRecoveryRevisionRef.current === forkRecoverySnapshot.revision)
216
+ return;
217
+ forkRecoveryRevisionRef.current = forkRecoverySnapshot.revision;
218
+ if (mode !== 'worktree' || manager === undefined)
219
+ return;
220
+ void refresh({
221
+ preserveCurrent: readStateRef.current.status === 'ready',
222
+ invalidateContext: false,
223
+ }).catch(() => {
224
+ // Recovery state remains visible; the next explicit retry can refresh it again.
225
+ });
226
+ }, [forkRecoverySnapshot.revision, manager, mode, refresh]);
167
227
  useEffect(() => {
168
228
  if (readState.status !== 'ready' || syncSessionWorkspaces === undefined)
169
229
  return;
@@ -173,6 +233,60 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
173
233
  }))));
174
234
  }, [readState.status, readState.views, syncSessionWorkspaces]);
175
235
  const viewByWorkspace = useMemo(() => new Map(readState.views.map((view) => [view.workspaceId, view])), [readState.views]);
236
+ const sessionOrderInputs = useMemo(() => {
237
+ if (readState.status !== 'ready')
238
+ return [];
239
+ const inputs = [];
240
+ for (const workspace of workspaces.items) {
241
+ const view = viewByWorkspace.get(workspace.workspaceId);
242
+ const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
243
+ const bindings = view?.bindings ?? [];
244
+ const boundSessionIds = new Set(bindings.map((binding) => binding.sessionId));
245
+ const mainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...boundSessionIds]), sessions);
246
+ inputs.push({
247
+ accountKey: `main:${workspace.workspaceId}`,
248
+ sessionIds: mainSessionIds,
249
+ updatedAtById: updatedAtById(mainSessionIds, sessions),
250
+ });
251
+ for (const record of view?.worktrees ?? []) {
252
+ const worktreeSessionIds = filterVisibleSessionIds(filterArchivedSessionIds(bindingIdsFor(bindings, record.worktreeId).filter((sessionId) => sessions.ids.includes(sessionId)), archivedSessionIds), sessions);
253
+ inputs.push({
254
+ accountKey: `worktree:${record.worktreeId}`,
255
+ sessionIds: worktreeSessionIds,
256
+ updatedAtById: updatedAtById(worktreeSessionIds, sessions),
257
+ });
258
+ }
259
+ }
260
+ return inputs;
261
+ }, [
262
+ archivedSessionIds,
263
+ readState.status,
264
+ sessions.byId,
265
+ sessions.ids,
266
+ viewByWorkspace,
267
+ workspaces,
268
+ workspaces.items,
269
+ ]);
270
+ const orderedSessionIdsByAccount = useMemo(() => {
271
+ const ordered = new Map();
272
+ for (const input of sessionOrderInputs) {
273
+ const previous = sessionOrderSnapshot.accounts[input.accountKey];
274
+ ordered.set(input.accountKey, nextSessionOrderAccount({
275
+ baseIds: input.sessionIds,
276
+ updatedAtById: input.updatedAtById,
277
+ previous,
278
+ }).order);
279
+ }
280
+ return ordered;
281
+ }, [sessionOrderInputs, sessionOrderSnapshot]);
282
+ useEffect(() => {
283
+ if (mode !== 'worktree' || readState.status !== 'ready')
284
+ return;
285
+ for (const input of sessionOrderInputs) {
286
+ sessionOrder.actions.reconcile(input.accountKey, input.sessionIds, input.updatedAtById);
287
+ }
288
+ sessionOrder.actions.retain(sessionOrderInputs.map((input) => input.accountKey));
289
+ }, [mode, readState.status, sessionOrder, sessionOrderInputs]);
176
290
  const currentSessionLocation = useMemo(() => readState.status === 'ready'
177
291
  ? resolveCurrentSessionLocation(currentSessionId, workspaces.items, readState.views)
178
292
  : undefined, [currentSessionId, readState.status, readState.views, workspaces.items]);
@@ -238,11 +352,11 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
238
352
  const modalSetupStatus = modalView === undefined
239
353
  ? undefined
240
354
  : modalReadiness?.status === 'ready'
241
- ? modalView.branches.length === 0 ? 'noLocalBranch' : undefined
355
+ ? modalView.branches.length === 0
356
+ ? 'noLocalBranch'
357
+ : undefined
242
358
  : modalReadiness?.status;
243
- const modalCanCreate = !modalReadLoading &&
244
- modalSetupStatus === undefined &&
245
- modalReadiness?.status === 'ready';
359
+ const modalCanCreate = !modalReadLoading && modalSetupStatus === undefined && modalReadiness?.status === 'ready';
246
360
  useEffect(() => {
247
361
  if (worktreeModalWorkspaceId === undefined || modalView === undefined)
248
362
  return;
@@ -388,9 +502,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
388
502
  const sourceIndex = rows.findIndex((workspace) => workspace.workspaceId === activeDrag.workspaceId);
389
503
  if (targetIndex === -1 || sourceIndex === -1)
390
504
  return;
391
- const beforeWorkspaceId = over.half === 'before'
392
- ? over.workspaceId
393
- : rows[targetIndex + 1]?.workspaceId;
505
+ const beforeWorkspaceId = over.half === 'before' ? over.workspaceId : rows[targetIndex + 1]?.workspaceId;
394
506
  const anchorIndex = beforeWorkspaceId === undefined
395
507
  ? rows.length
396
508
  : rows.findIndex((workspace) => workspace.workspaceId === beforeWorkspaceId);
@@ -421,12 +533,8 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
421
533
  const sourceIndex = sessionIds.indexOf(activeDrag.sessionId);
422
534
  if (targetIndex === -1 || sourceIndex === -1)
423
535
  return;
424
- const beforeSessionId = over.half === 'before'
425
- ? over.sessionId
426
- : sessionIds[targetIndex + 1];
427
- const anchorIndex = beforeSessionId === undefined
428
- ? sessionIds.length
429
- : sessionIds.indexOf(beforeSessionId);
536
+ const beforeSessionId = over.half === 'before' ? over.sessionId : sessionIds[targetIndex + 1];
537
+ const anchorIndex = beforeSessionId === undefined ? sessionIds.length : sessionIds.indexOf(beforeSessionId);
430
538
  if (beforeSessionId === activeDrag.sessionId ||
431
539
  anchorIndex === sourceIndex ||
432
540
  anchorIndex === sourceIndex + 1) {
@@ -441,7 +549,12 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
441
549
  return;
442
550
  }
443
551
  setActionError(undefined);
444
- void insertSessionBefore(workspaceId, activeDrag.sessionId, beforeSessionId).catch((error) => {
552
+ const currentOrder = sessionOrderSnapshot.accounts[activeDrag.groupKey]?.order ?? sessionIds;
553
+ void insertSessionBefore(workspaceId, activeDrag.sessionId, beforeSessionId)
554
+ .then(() => {
555
+ sessionOrder.actions.setOrder(activeDrag.groupKey, reorderSessionIds(currentOrder, activeDrag.sessionId, over.sessionId, over.half));
556
+ })
557
+ .catch((error) => {
445
558
  setActionError(toWorktreeViewError(error));
446
559
  });
447
560
  };
@@ -582,8 +695,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
582
695
  if (visuallyExpanded)
583
696
  clearSessionGroups(['worktree:' + worktreeId]);
584
697
  };
585
- const toggleSessionGroup = (groupKey) => {
586
- const autoExpanded = isCurrentSessionReveal('session-group:' + groupKey);
698
+ const toggleSessionGroup = (groupKey, autoExpanded) => {
587
699
  const transientExpanded = expandedSessionGroups[groupKey] === true;
588
700
  if (autoExpanded) {
589
701
  suppressCurrentSessionReveal('session-group:' + groupKey);
@@ -609,7 +721,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
609
721
  setModalReadError(undefined);
610
722
  setModalReadLoading(false);
611
723
  };
612
- const openWorktreeCreator = (workspace) => {
724
+ const openWorktreeCreator = (workspace, defaults = {}) => {
613
725
  const view = viewByWorkspace.get(workspace.workspaceId);
614
726
  modalReadLoader.current.invalidate();
615
727
  modalReadViewRef.current = undefined;
@@ -622,13 +734,13 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
622
734
  setModalReadError(undefined);
623
735
  setModalReadLoading(false);
624
736
  if (view === undefined) {
625
- setSelectedBranch('');
626
- setNewBranch('');
737
+ setSelectedBranch(defaults.baseBranch ?? '');
738
+ setNewBranch(defaults.newBranch ?? '');
627
739
  loadModalWorktreeView(workspace.workspaceId);
628
740
  return;
629
741
  }
630
- setSelectedBranch(selectDefaultBaseBranch(view.branches));
631
- setNewBranch(createDefaultWorktreeName([
742
+ setSelectedBranch(defaults.baseBranch ?? selectDefaultBaseBranch(view.branches));
743
+ setNewBranch(defaults.newBranch ?? createDefaultWorktreeName([
632
744
  ...view.branches.map((branch) => branch.name),
633
745
  ...view.worktrees.map((worktree) => worktree.branch),
634
746
  ]));
@@ -665,6 +777,13 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
665
777
  if (error instanceof WorktreeSessionBindingError && error.retryable) {
666
778
  setPendingSessionBinding({ ...sessionInput, sessionId: error.sessionId });
667
779
  }
780
+ if (error instanceof WorktreeSessionPermissionError && error.retryable) {
781
+ setPendingSessionBinding({
782
+ ...sessionInput,
783
+ sessionId: error.sessionId,
784
+ permissionRequired: true,
785
+ });
786
+ }
668
787
  throw error;
669
788
  }
670
789
  await refresh({ preserveCurrent: true });
@@ -736,6 +855,13 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
736
855
  if (error instanceof WorktreeSessionBindingError && error.retryable) {
737
856
  setPendingSessionBinding({ ...input, sessionId: error.sessionId });
738
857
  }
858
+ if (error instanceof WorktreeSessionPermissionError && error.retryable) {
859
+ setPendingSessionBinding({
860
+ ...input,
861
+ sessionId: error.sessionId,
862
+ permissionRequired: true,
863
+ });
864
+ }
739
865
  setActionError(toWorktreeViewError(error));
740
866
  }
741
867
  finally {
@@ -743,9 +869,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
743
869
  }
744
870
  };
745
871
  const retrySessionBinding = async () => {
746
- if (manager === undefined ||
747
- pendingSessionBinding === undefined ||
748
- pendingSessionArchived)
872
+ if (manager === undefined || pendingSessionBinding === undefined || pendingSessionArchived)
749
873
  return;
750
874
  const pending = pendingSessionBinding;
751
875
  setActionPending(true);
@@ -758,6 +882,9 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
758
882
  ensureSessionWorkspace: (workspaceId, sessionId) => {
759
883
  ensureSessionWorkspace?.(workspaceId, sessionId);
760
884
  },
885
+ permission,
886
+ confirmFullAccess,
887
+ onPermissionResult,
761
888
  openSession,
762
889
  });
763
890
  setPendingSessionBinding(undefined);
@@ -774,6 +901,20 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
774
901
  setActionPending(false);
775
902
  }
776
903
  };
904
+ const retryForkBinding = async (key) => {
905
+ if (retryForkSession === undefined || forkRetryKey !== undefined)
906
+ return;
907
+ setForkRetryKey(key);
908
+ try {
909
+ await retryForkSession(key);
910
+ }
911
+ catch (error) {
912
+ setActionError(toNativeWorktreeViewError(error));
913
+ }
914
+ finally {
915
+ setForkRetryKey(undefined);
916
+ }
917
+ };
777
918
  const openWorkspaceSession = (workspaceId, sessionId) => {
778
919
  ensureSessionWorkspace?.(workspaceId, sessionId);
779
920
  openWorktreeSession({ open: openSession }, sessionId);
@@ -793,14 +934,21 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
793
934
  } }), _jsx("button", { type: "button", className: styles.iconButton, "aria-label": t('workspace.add'), onClick: () => {
794
935
  if (createWorkspace !== undefined)
795
936
  void runMutation(createWorkspace);
796
- }, children: _jsx(IconPlusOutline16, {}) })] }), _jsxs("div", { className: styles.content, tabIndex: 0, children: [actionError !== undefined && (_jsxs("div", { className: styles.error, role: "alert", "data-worktree-error": true, children: [_jsx("p", { className: styles.message, "data-error": "true", children: formatWorktreeViewError(actionError, t) }), pendingSessionBinding !== undefined && (_jsxs("div", { className: styles.recoveryActions, children: [_jsx("button", { type: "button", className: styles.actionButton, disabled: actionPending || pendingSessionArchived, onClick: () => {
937
+ }, children: _jsx(IconProjectAddOutline16, {}) })] }), _jsxs("div", { className: styles.content, tabIndex: 0, children: [permissionNoticeSnapshot !== undefined && (_jsx("div", { className: styles.notice, role: "status", "data-worktree-permission-notice": true, children: _jsx("p", { className: styles.message, children: formatWorktreePermissionNotice(permissionNoticeSnapshot.result, t) }) })), forkRecoverySnapshot.pending.map((recovery) => {
938
+ const recoveryViewError = forkRecoveryError(recovery);
939
+ return (_jsxs("div", { className: styles.error, role: "alert", "data-fork-recovery": recovery.key, children: [_jsx("p", { className: styles.message, "data-error": "true", children: formatWorktreeViewError(recoveryViewError, t) }), _jsxs("div", { className: styles.recoveryActions, children: [retryForkSession !== undefined && recoveryViewError.retryable && (_jsx("button", { type: "button", className: styles.actionButton, disabled: forkRetryKey !== undefined, onClick: () => {
940
+ void retryForkBinding(recovery.key);
941
+ }, children: t('action.retryBinding') })), _jsx("button", { type: "button", className: styles.actionButton, disabled: forkRetryKey !== undefined, onClick: () => {
942
+ openSession(recovery.childSessionId);
943
+ }, children: t('action.openCreatedSession') })] })] }, recovery.key));
944
+ }), actionError !== undefined && (_jsxs("div", { className: styles.error, role: "alert", "data-worktree-error": true, children: [_jsx("p", { className: styles.message, "data-error": "true", children: formatWorktreeViewError(actionError, t) }), pendingSessionBinding !== undefined && (_jsxs("div", { className: styles.recoveryActions, children: [_jsx("button", { type: "button", className: styles.actionButton, disabled: actionPending || pendingSessionArchived, onClick: () => {
797
945
  void retrySessionBinding();
798
- }, children: t('action.retryBinding') }), _jsx("button", { type: "button", className: styles.actionButton, disabled: actionPending, onClick: () => {
946
+ }, children: t('action.retryBinding') }), !pendingSessionBinding.permissionRequired && (_jsx("button", { type: "button", className: styles.actionButton, disabled: actionPending, onClick: () => {
799
947
  const sessionId = pendingSessionBinding.sessionId;
800
948
  setPendingSessionBinding(undefined);
801
949
  setActionError(undefined);
802
950
  openSession(sessionId);
803
- }, children: t('action.openCreatedSession') })] })), actionError.retryable && (_jsx("button", { type: "button", className: styles.retryButton, onClick: () => {
951
+ }, children: t('action.openCreatedSession') }))] })), actionError.retryable && (_jsx("button", { type: "button", className: styles.retryButton, onClick: () => {
804
952
  setActionError(undefined);
805
953
  void refresh();
806
954
  }, children: t('action.retry') }))] })), readState.status === 'loading' && (_jsx("p", { className: styles.message, children: t('status.loading') })), readState.status === 'error' && readState.error !== undefined ? (_jsxs("div", { className: styles.error, role: "alert", "data-worktree-error": true, children: [_jsx("p", { className: styles.message, "data-error": "true", children: formatWorktreeViewError(readState.error, t) }), _jsx("button", { type: "button", className: styles.retryButton, onClick: () => {
@@ -815,20 +963,30 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
815
963
  isCurrentSessionReveal('workspace:' + workspace.workspaceId);
816
964
  const workspaceMatchesQuery = includesText(workspace.title, query);
817
965
  const allWorkspaceSessionIds = filterArchivedSessionIds(workspaceSessionIds(workspaces, workspace.workspaceId, sessions.ids), archivedSessionIds);
966
+ const workspaceActivitySessionIds = filterVisibleSessionIds(allWorkspaceSessionIds, sessions);
967
+ const workspaceHasOngoingSession = hasOngoingSession(workspaceActivitySessionIds, sessionPresentations);
818
968
  const bindings = view?.bindings ?? [];
819
969
  const boundSessionIds = new Set(bindings.map((binding) => binding.sessionId));
820
970
  const mainSessionIds = filterVisibleSessionIds(unboundSessionIds(allWorkspaceSessionIds, [...boundSessionIds]), sessions);
971
+ const mainGroupKey = `main:${workspace.workspaceId}`;
972
+ const orderedMainSessionIds = orderedSessionIdsByAccount.get(mainGroupKey) ?? mainSessionIds;
821
973
  const visibleMainSessionIds = mainSessionIds.filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
974
+ const orderedVisibleMainSessionIds = orderedMainSessionIds.filter((sessionId) => workspaceMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
822
975
  const mainExpanded = isMainExpanded(expandSnapshot, workspace.workspaceId) ||
823
976
  isCurrentSessionReveal('main:' + workspace.workspaceId);
824
- const mainGroupKey = `main:${workspace.workspaceId}`;
825
- const sessionIds = visibleMainSessionIds;
977
+ const sessionIds = orderedVisibleMainSessionIds.length === visibleMainSessionIds.length
978
+ ? orderedVisibleMainSessionIds
979
+ : visibleMainSessionIds;
980
+ const mainSessionGroupAutoExpanded = isSessionGroupAutoExpanded(sessionIds, currentSessionId, isCurrentSessionReveal('session-group:' + mainGroupKey));
826
981
  const mainSessionGroupExpanded = expandedSessionGroups[mainGroupKey] === true ||
827
- (sessionIds.length > 5 &&
828
- isCurrentSessionReveal('session-group:' + mainGroupKey));
982
+ mainSessionGroupAutoExpanded;
829
983
  const worktrees = view?.worktrees ?? [];
984
+ const workspaceWorktreeNames = [
985
+ ...(view?.branches.map((branch) => branch.name) ?? []),
986
+ ...(view?.worktrees.map((worktree) => worktree.branch) ?? []),
987
+ ];
830
988
  const sameWorkspaceWorktreeDrag = worktreeDrag?.workspaceId === workspace.workspaceId;
831
- return (_jsxs("section", { className: styles.workspaceGroup, "data-workspace-id": workspace.workspaceId, children: [_jsx(WorktreeWorkspaceRow, { t: t, workspace: workspace, expanded: expanded, actionPending: actionPending, menuOpen: openWorkspaceMenuId === workspace.workspaceId, drag: {
989
+ return (_jsxs("section", { className: styles.workspaceGroup, "data-workspace-id": workspace.workspaceId, children: [_jsx(WorktreeWorkspaceRow, { t: t, workspace: workspace, expanded: expanded, hasOngoingSession: workspaceHasOngoingSession, actionPending: actionPending, menuOpen: openWorkspaceMenuId === workspace.workspaceId, drag: {
832
990
  active: workspaceDrag !== undefined,
833
991
  marker: workspaceDrag?.over?.workspaceId === workspace.workspaceId
834
992
  ? workspaceDrag.over.half
@@ -872,14 +1030,32 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
872
1030
  openWorkspaceDelete(workspace);
873
1031
  }, onMenuOpenChange: (open) => {
874
1032
  setOpenWorkspaceMenuId(open ? workspace.workspaceId : undefined);
875
- } }), expanded && (_jsxs("div", { className: styles.treeChildren, children: [_jsx(WorktreeGroupRow, { t: t, kind: "main", label: mainLabel, expanded: mainExpanded, icon: _jsx(IconBranchOutline16, {}), workspaceTitle: workspace.title, onToggle: () => {
1033
+ } }), expanded && (_jsxs("div", { className: styles.treeChildren, children: [_jsx(WorktreeGroupRow, { t: t, kind: "main", label: mainLabel, expanded: mainExpanded, hasOngoingSession: hasOngoingSession(mainSessionIds, sessionPresentations), icon: _jsx(IconBranchOutline16, {}), workspaceTitle: workspace.title, onToggle: () => {
876
1034
  toggleMain(workspace.workspaceId);
1035
+ }, menu: {
1036
+ open: openMainMenuId === workspace.workspaceId,
1037
+ label: mainLabel,
1038
+ copyPath: workspace.path,
1039
+ showCreate: currentBranch !== undefined,
1040
+ showRemove: false,
1041
+ disabled: actionPending,
1042
+ onOpenChange: (open) => {
1043
+ setOpenMainMenuId(open ? workspace.workspaceId : undefined);
1044
+ },
1045
+ onCreateWorktree: currentBranch === undefined
1046
+ ? undefined
1047
+ : () => {
1048
+ openWorktreeCreator(workspace, {
1049
+ baseBranch: currentBranch,
1050
+ newBranch: createNumberedWorktreeName(currentBranch, workspaceWorktreeNames),
1051
+ });
1052
+ },
877
1053
  }, onCreateSession: createMainSession === undefined
878
1054
  ? undefined
879
1055
  : () => {
880
1056
  createMainSession(workspace.workspaceId);
881
- } }), mainExpanded && (_jsx(WorktreeSessionGroup, { t: t, groupKey: mainGroupKey, sessionIds: sessionIds, workspaceId: workspace.workspaceId, currentSessionId: currentSessionId, expanded: mainSessionGroupExpanded, actionPending: actionPending, sessions: sessions, dragState: sessionDrag, onToggleExpanded: () => {
882
- toggleSessionGroup(mainGroupKey);
1057
+ } }), mainExpanded && (_jsx(WorktreeSessionGroup, { t: t, groupKey: mainGroupKey, sessionIds: sessionIds, workspaceId: workspace.workspaceId, currentSessionId: currentSessionId, expanded: mainSessionGroupExpanded, actionPending: actionPending, sessions: sessions, sessionPresentations: sessionPresentations, dragState: sessionDrag, onToggleExpanded: () => {
1058
+ toggleSessionGroup(mainGroupKey, mainSessionGroupAutoExpanded);
883
1059
  }, onStartDrag: (groupKey, sessionId) => {
884
1060
  sessionDropCommitted.current = false;
885
1061
  setSessionDrag({ groupKey, sessionId, over: null });
@@ -903,12 +1079,20 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
903
1079
  !worktreeSessionIds.some((sessionId) => sessionMatchesQuery(sessionId, sessions, query))) {
904
1080
  return null;
905
1081
  }
906
- const visibleWorktreeSessionIds = worktreeSessionIds.filter((sessionId) => worktreeMatchesQuery || sessionMatchesQuery(sessionId, sessions, query));
1082
+ const visibleWorktreeSessionIds = worktreeSessionIds.filter((sessionId) => worktreeMatchesQuery ||
1083
+ sessionMatchesQuery(sessionId, sessions, query));
907
1084
  const worktreeGroupKey = `worktree:${record.worktreeId}`;
908
- const sessionIds = visibleWorktreeSessionIds;
1085
+ const orderedWorktreeSessionIds = orderedSessionIdsByAccount.get(worktreeGroupKey) ??
1086
+ worktreeSessionIds;
1087
+ const orderedVisibleWorktreeSessionIds = orderedWorktreeSessionIds.filter((sessionId) => worktreeMatchesQuery ||
1088
+ sessionMatchesQuery(sessionId, sessions, query));
1089
+ const sessionIds = orderedVisibleWorktreeSessionIds.length ===
1090
+ visibleWorktreeSessionIds.length
1091
+ ? orderedVisibleWorktreeSessionIds
1092
+ : visibleWorktreeSessionIds;
1093
+ const sessionGroupAutoExpanded = isSessionGroupAutoExpanded(sessionIds, currentSessionId, isCurrentSessionReveal('session-group:' + worktreeGroupKey));
909
1094
  const sessionGroupExpanded = expandedSessionGroups[worktreeGroupKey] === true ||
910
- (sessionIds.length > 5 &&
911
- isCurrentSessionReveal('session-group:' + worktreeGroupKey));
1095
+ sessionGroupAutoExpanded;
912
1096
  const state = record.status === 'removed'
913
1097
  ? 'warning'
914
1098
  : record.health === 'repair'
@@ -921,7 +1105,7 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
921
1105
  : t('worktree.ready');
922
1106
  const worktreeExpanded = isWorktreeExpanded(expandSnapshot, record.worktreeId) ||
923
1107
  isCurrentSessionReveal('worktree:' + record.worktreeId);
924
- return (_jsxs("div", { className: styles.worktreeGroup, "data-worktree-id": record.worktreeId, children: [_jsx(WorktreeGroupRow, { t: t, kind: "worktree", label: record.branch, worktreeId: record.worktreeId, expanded: worktreeExpanded, icon: _jsx(IconBranchOutline16, {}), workspaceTitle: workspace.title, state: state, stateLabel: stateLabel, onToggle: () => {
1108
+ return (_jsxs("div", { className: styles.worktreeGroup, "data-worktree-id": record.worktreeId, children: [_jsx(WorktreeGroupRow, { t: t, kind: "worktree", label: record.branch, worktreeId: record.worktreeId, expanded: worktreeExpanded, hasOngoingSession: hasOngoingSession(worktreeSessionIds, sessionPresentations), icon: _jsx(IconBranchOutline16, {}), workspaceTitle: workspace.title, state: state, stateLabel: stateLabel, onToggle: () => {
925
1109
  toggleWorktree(record.worktreeId);
926
1110
  }, onCreateSession: record.status === 'active' && record.health !== 'repair'
927
1111
  ? () => {
@@ -931,20 +1115,31 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
931
1115
  cwd: record.absolutePath,
932
1116
  });
933
1117
  }
934
- : undefined, menu: record.status === 'active'
935
- ? {
936
- open: openWorktreeMenuId === record.worktreeId,
937
- label: record.branch,
938
- disabled: actionPending,
939
- onOpenChange: (open) => {
940
- setOpenWorktreeMenuId(open ? record.worktreeId : undefined);
941
- },
942
- onRemove: () => {
1118
+ : undefined, menu: {
1119
+ open: openWorktreeMenuId === record.worktreeId,
1120
+ label: record.branch,
1121
+ copyPath: record.absolutePath,
1122
+ showCreate: record.status === 'active',
1123
+ showRemove: record.status === 'active',
1124
+ disabled: actionPending,
1125
+ onOpenChange: (open) => {
1126
+ setOpenWorktreeMenuId(open ? record.worktreeId : undefined);
1127
+ },
1128
+ onCreateWorktree: record.status === 'active'
1129
+ ? () => {
1130
+ openWorktreeCreator(workspace, {
1131
+ baseBranch: record.branch,
1132
+ newBranch: createNumberedWorktreeName(record.branch, workspaceWorktreeNames),
1133
+ });
1134
+ }
1135
+ : undefined,
1136
+ onRemove: record.status === 'active'
1137
+ ? () => {
943
1138
  setWorktreeRemoval(record);
944
1139
  setActionError(undefined);
945
- },
946
- }
947
- : undefined, drag: {
1140
+ }
1141
+ : undefined,
1142
+ }, drag: {
948
1143
  active: sameWorkspaceWorktreeDrag,
949
1144
  marker: worktreeDrag?.over?.worktreeId === record.worktreeId
950
1145
  ? worktreeDrag.over.half
@@ -975,8 +1170,8 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
975
1170
  setWorktreeDrag(undefined);
976
1171
  worktreeDropCommitted.current = false;
977
1172
  },
978
- } }), worktreeExpanded && (_jsx(WorktreeSessionGroup, { t: t, groupKey: worktreeGroupKey, sessionIds: sessionIds, workspaceId: workspace.workspaceId, currentSessionId: currentSessionId, expanded: sessionGroupExpanded, actionPending: actionPending, sessions: sessions, dragState: sessionDrag, onToggleExpanded: () => {
979
- toggleSessionGroup(worktreeGroupKey);
1173
+ } }), worktreeExpanded && (_jsx(WorktreeSessionGroup, { t: t, groupKey: worktreeGroupKey, sessionIds: sessionIds, workspaceId: workspace.workspaceId, currentSessionId: currentSessionId, expanded: sessionGroupExpanded, actionPending: actionPending, sessions: sessions, sessionPresentations: sessionPresentations, dragState: sessionDrag, onToggleExpanded: () => {
1174
+ toggleSessionGroup(worktreeGroupKey, sessionGroupAutoExpanded);
980
1175
  }, onStartDrag: (groupKey, sessionId) => {
981
1176
  sessionDropCommitted.current = false;
982
1177
  setSessionDrag({ groupKey, sessionId, over: null });
@@ -1024,10 +1219,20 @@ export function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces,
1024
1219
  workspaceId: target.workspaceId,
1025
1220
  worktreeId: target.worktreeId,
1026
1221
  },
1027
- });
1222
+ }, permission, onPermissionNotice);
1028
1223
  await invalidateWorktreeContext?.(target.workspaceId);
1029
1224
  setWorktreeRemoval(undefined);
1030
1225
  });
1226
+ } }), _jsx(RiskConfirmation, { open: fullAccessConfirmationSnapshot !== undefined, title: t('permission.fullAccessTitle'), description: fullAccessConfirmationSnapshot === undefined
1227
+ ? ''
1228
+ : t('permission.fullAccessDescription', {
1229
+ cwd: fullAccessConfirmationSnapshot.cwd,
1230
+ }), acknowledgeLabel: t('permission.fullAccessAcknowledge'), cancelLabel: t('dialog.cancel'), confirmLabel: t('permission.fullAccessEnable'), acknowledged: fullAccessAcknowledged, onAcknowledgedChange: setFullAccessAcknowledged, onCancel: () => {
1231
+ setFullAccessAcknowledged(false);
1232
+ fullAccessConfirmation?.resolve(false);
1233
+ }, onConfirm: () => {
1234
+ setFullAccessAcknowledged(false);
1235
+ fullAccessConfirmation?.resolve(true);
1031
1236
  } })] }));
1032
1237
  }
1033
1238
  //# sourceMappingURL=WorktreeSurface.js.map