@cerbur/clutch-dsh-worktree 0.1.8 → 0.1.9

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 (84) hide show
  1. package/README.md +18 -23
  2. package/README.zh.md +17 -21
  3. package/lib/client/WorktreeContext.d.ts +1 -1
  4. package/lib/client/WorktreeContext.d.ts.map +1 -1
  5. package/lib/client/WorktreeContext.js +1 -1
  6. package/lib/client/WorktreeContext.js.map +1 -1
  7. package/lib/client/WorktreeHeroContext.d.ts.map +1 -1
  8. package/lib/client/WorktreeHeroContext.js +1 -1
  9. package/lib/client/WorktreeHeroContext.js.map +1 -1
  10. package/lib/client/WorktreeModeAction.d.ts.map +1 -1
  11. package/lib/client/WorktreeModeAction.js.map +1 -1
  12. package/lib/client/WorktreeSurface.d.ts +1 -1
  13. package/lib/client/WorktreeSurface.d.ts.map +1 -1
  14. package/lib/client/WorktreeSurface.js +221 -45
  15. package/lib/client/WorktreeSurface.js.map +1 -1
  16. package/lib/client/dsh-rc1-slot-contract.d.ts +43 -0
  17. package/lib/client/dsh-rc1-slot-contract.d.ts.map +1 -0
  18. package/lib/client/dsh-rc1-slot-contract.js +2 -0
  19. package/lib/client/dsh-rc1-slot-contract.js.map +1 -0
  20. package/lib/client/dsh-slot-contract.d.ts +43 -0
  21. package/lib/client/dsh-slot-contract.d.ts.map +1 -0
  22. package/lib/client/dsh-slot-contract.js +2 -0
  23. package/lib/client/dsh-slot-contract.js.map +1 -0
  24. package/lib/client/entry.d.ts +2 -2
  25. package/lib/client/entry.d.ts.map +1 -1
  26. package/lib/client/entry.js +144 -26
  27. package/lib/client/entry.js.map +1 -1
  28. package/lib/client/view-mode-store.d.ts +1 -1
  29. package/lib/client/view-mode-store.d.ts.map +1 -1
  30. package/lib/client/view-mode-store.js +1 -1
  31. package/lib/client/view-mode-store.js.map +1 -1
  32. package/lib/client/view-mode.d.ts +20 -6
  33. package/lib/client/view-mode.d.ts.map +1 -1
  34. package/lib/client/view-mode.js +35 -10
  35. package/lib/client/view-mode.js.map +1 -1
  36. package/lib/client/virtual-workspace-membership.d.ts +12 -10
  37. package/lib/client/virtual-workspace-membership.d.ts.map +1 -1
  38. package/lib/client/virtual-workspace-membership.js +82 -57
  39. package/lib/client/virtual-workspace-membership.js.map +1 -1
  40. package/lib/client/worktree-context-store.d.ts +7 -15
  41. package/lib/client/worktree-context-store.d.ts.map +1 -1
  42. package/lib/client/worktree-context-store.js +20 -13
  43. package/lib/client/worktree-context-store.js.map +1 -1
  44. package/lib/client/worktree-expand-state.d.ts +5 -4
  45. package/lib/client/worktree-expand-state.d.ts.map +1 -1
  46. package/lib/client/worktree-expand-state.js.map +1 -1
  47. package/lib/client/worktree-session-fork.d.ts +18 -3
  48. package/lib/client/worktree-session-fork.d.ts.map +1 -1
  49. package/lib/client/worktree-session-fork.js +125 -36
  50. package/lib/client/worktree-session-fork.js.map +1 -1
  51. package/lib/client/worktree-session-order.d.ts +2 -2
  52. package/lib/client/worktree-session-order.d.ts.map +1 -1
  53. package/lib/client/worktree-surface-rows.d.ts.map +1 -1
  54. package/lib/client/worktree-surface-rows.js +1 -1
  55. package/lib/client/worktree-surface-rows.js.map +1 -1
  56. package/lib/client/worktree-surface-types.d.ts +19 -1
  57. package/lib/client/worktree-surface-types.d.ts.map +1 -1
  58. package/lib/client/worktree-view-read.d.ts +18 -8
  59. package/lib/client/worktree-view-read.d.ts.map +1 -1
  60. package/lib/client/worktree-view-read.js +75 -10
  61. package/lib/client/worktree-view-read.js.map +1 -1
  62. package/lib/client.js +1359 -169
  63. package/lib/client.js.map +1 -1
  64. package/lib/host/worktree-permission.d.ts +3 -2
  65. package/lib/host/worktree-permission.d.ts.map +1 -1
  66. package/lib/host/worktree-permission.js +29 -5
  67. package/lib/host/worktree-permission.js.map +1 -1
  68. package/lib/manage/manager-worktrees.d.ts.map +1 -1
  69. package/lib/manage/manager-worktrees.js +5 -2
  70. package/lib/manage/manager-worktrees.js.map +1 -1
  71. package/lib/manage/manager.d.ts.map +1 -1
  72. package/lib/manage/manager.js +2 -0
  73. package/lib/manage/manager.js.map +1 -1
  74. package/lib/provider/git.d.ts.map +1 -1
  75. package/lib/provider/git.js +4 -0
  76. package/lib/provider/git.js.map +1 -1
  77. package/lib/provider/sidecar.js +1 -1
  78. package/lib/provider/sidecar.js.map +1 -1
  79. package/lib/provider/subprocess.d.ts.map +1 -1
  80. package/lib/provider/subprocess.js +8 -0
  81. package/lib/provider/subprocess.js.map +1 -1
  82. package/lib/provider/transaction.js +2 -2
  83. package/lib/provider/transaction.js.map +1 -1
  84. package/package.json +48 -34
package/lib/client.js CHANGED
@@ -4,10 +4,755 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
8
7
  let react_jsx_runtime = require("react/jsx-runtime");
9
8
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
9
  let react = require("react");
10
+ //#region ../../node_modules/.pnpm/zustand@4.4.7_@types+react@18.3.31_immer@10.2.0_react@18.3.1/node_modules/zustand/esm/vanilla.mjs
11
+ const createStoreImpl = (createState) => {
12
+ let state;
13
+ const listeners = /* @__PURE__ */ new Set();
14
+ const setState = (partial, replace) => {
15
+ const nextState = typeof partial === "function" ? partial(state) : partial;
16
+ if (!Object.is(nextState, state)) {
17
+ const previousState = state;
18
+ state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
19
+ listeners.forEach((listener) => listener(state, previousState));
20
+ }
21
+ };
22
+ const getState = () => state;
23
+ const subscribe = (listener) => {
24
+ listeners.add(listener);
25
+ return () => listeners.delete(listener);
26
+ };
27
+ const destroy = () => {
28
+ listeners.clear();
29
+ };
30
+ const api = {
31
+ setState,
32
+ getState,
33
+ subscribe,
34
+ destroy
35
+ };
36
+ state = createState(setState, getState, api);
37
+ return api;
38
+ };
39
+ const createStore = (createState) => createState ? createStoreImpl(createState) : createStoreImpl;
40
+ //#endregion
41
+ //#region ../../node_modules/.pnpm/zustand@4.4.7_@types+react@18.3.31_immer@10.2.0_react@18.3.1/node_modules/zustand/esm/middleware.mjs
42
+ const subscribeWithSelectorImpl = (fn) => (set, get, api) => {
43
+ const origSubscribe = api.subscribe;
44
+ api.subscribe = (selector, optListener, options) => {
45
+ let listener = selector;
46
+ if (optListener) {
47
+ const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is;
48
+ let currentSlice = selector(api.getState());
49
+ listener = (state) => {
50
+ const nextSlice = selector(state);
51
+ if (!equalityFn(currentSlice, nextSlice)) {
52
+ const previousSlice = currentSlice;
53
+ optListener(currentSlice = nextSlice, previousSlice);
54
+ }
55
+ };
56
+ if (options == null ? void 0 : options.fireImmediately) optListener(currentSlice, currentSlice);
57
+ }
58
+ return origSubscribe(listener);
59
+ };
60
+ return fn(set, get, api);
61
+ };
62
+ const subscribeWithSelector = subscribeWithSelectorImpl;
63
+ //#endregion
64
+ //#region ../../node_modules/.pnpm/immer@10.2.0/node_modules/immer/dist/immer.mjs
65
+ var NOTHING = Symbol.for("immer-nothing");
66
+ var DRAFTABLE = Symbol.for("immer-draftable");
67
+ var DRAFT_STATE = Symbol.for("immer-state");
68
+ function die(error, ...args) {
69
+ throw new Error(`[Immer] minified error nr: ${error}. Full error at: https://bit.ly/3cXEKWf`);
70
+ }
71
+ var getPrototypeOf = Object.getPrototypeOf;
72
+ function isDraft(value) {
73
+ return !!value && !!value[DRAFT_STATE];
74
+ }
75
+ function isDraftable(value) {
76
+ if (!value) return false;
77
+ return isPlainObject(value) || Array.isArray(value) || !!value[DRAFTABLE] || !!value.constructor?.[DRAFTABLE] || isMap(value) || isSet(value);
78
+ }
79
+ var objectCtorString = Object.prototype.constructor.toString();
80
+ var cachedCtorStrings = /* @__PURE__ */ new WeakMap();
81
+ function isPlainObject(value) {
82
+ if (!value || typeof value !== "object") return false;
83
+ const proto = Object.getPrototypeOf(value);
84
+ if (proto === null || proto === Object.prototype) return true;
85
+ const Ctor = Object.hasOwnProperty.call(proto, "constructor") && proto.constructor;
86
+ if (Ctor === Object) return true;
87
+ if (typeof Ctor !== "function") return false;
88
+ let ctorString = cachedCtorStrings.get(Ctor);
89
+ if (ctorString === void 0) {
90
+ ctorString = Function.toString.call(Ctor);
91
+ cachedCtorStrings.set(Ctor, ctorString);
92
+ }
93
+ return ctorString === objectCtorString;
94
+ }
95
+ function each(obj, iter, strict = true) {
96
+ if (getArchtype(obj) === 0) (strict ? Reflect.ownKeys(obj) : Object.keys(obj)).forEach((key) => {
97
+ iter(key, obj[key], obj);
98
+ });
99
+ else obj.forEach((entry, index) => iter(index, entry, obj));
100
+ }
101
+ function getArchtype(thing) {
102
+ const state = thing[DRAFT_STATE];
103
+ return state ? state.type_ : Array.isArray(thing) ? 1 : isMap(thing) ? 2 : isSet(thing) ? 3 : 0;
104
+ }
105
+ function has(thing, prop) {
106
+ return getArchtype(thing) === 2 ? thing.has(prop) : Object.prototype.hasOwnProperty.call(thing, prop);
107
+ }
108
+ function set(thing, propOrOldValue, value) {
109
+ const t = getArchtype(thing);
110
+ if (t === 2) thing.set(propOrOldValue, value);
111
+ else if (t === 3) thing.add(value);
112
+ else thing[propOrOldValue] = value;
113
+ }
114
+ function is(x, y) {
115
+ if (x === y) return x !== 0 || 1 / x === 1 / y;
116
+ else return x !== x && y !== y;
117
+ }
118
+ function isMap(target) {
119
+ return target instanceof Map;
120
+ }
121
+ function isSet(target) {
122
+ return target instanceof Set;
123
+ }
124
+ function latest(state) {
125
+ return state.copy_ || state.base_;
126
+ }
127
+ function shallowCopy(base, strict) {
128
+ if (isMap(base)) return new Map(base);
129
+ if (isSet(base)) return new Set(base);
130
+ if (Array.isArray(base)) return Array.prototype.slice.call(base);
131
+ const isPlain = isPlainObject(base);
132
+ if (strict === true || strict === "class_only" && !isPlain) {
133
+ const descriptors = Object.getOwnPropertyDescriptors(base);
134
+ delete descriptors[DRAFT_STATE];
135
+ let keys = Reflect.ownKeys(descriptors);
136
+ for (let i = 0; i < keys.length; i++) {
137
+ const key = keys[i];
138
+ const desc = descriptors[key];
139
+ if (desc.writable === false) {
140
+ desc.writable = true;
141
+ desc.configurable = true;
142
+ }
143
+ if (desc.get || desc.set) descriptors[key] = {
144
+ configurable: true,
145
+ writable: true,
146
+ enumerable: desc.enumerable,
147
+ value: base[key]
148
+ };
149
+ }
150
+ return Object.create(getPrototypeOf(base), descriptors);
151
+ } else {
152
+ const proto = getPrototypeOf(base);
153
+ if (proto !== null && isPlain) return { ...base };
154
+ const obj = Object.create(proto);
155
+ return Object.assign(obj, base);
156
+ }
157
+ }
158
+ function freeze(obj, deep = false) {
159
+ if (isFrozen(obj) || isDraft(obj) || !isDraftable(obj)) return obj;
160
+ if (getArchtype(obj) > 1) Object.defineProperties(obj, {
161
+ set: dontMutateMethodOverride,
162
+ add: dontMutateMethodOverride,
163
+ clear: dontMutateMethodOverride,
164
+ delete: dontMutateMethodOverride
165
+ });
166
+ Object.freeze(obj);
167
+ if (deep) Object.values(obj).forEach((value) => freeze(value, true));
168
+ return obj;
169
+ }
170
+ function dontMutateFrozenCollections() {
171
+ die(2);
172
+ }
173
+ var dontMutateMethodOverride = { value: dontMutateFrozenCollections };
174
+ function isFrozen(obj) {
175
+ if (obj === null || typeof obj !== "object") return true;
176
+ return Object.isFrozen(obj);
177
+ }
178
+ var plugins = {};
179
+ function getPlugin(pluginKey) {
180
+ const plugin = plugins[pluginKey];
181
+ if (!plugin) die(0, pluginKey);
182
+ return plugin;
183
+ }
184
+ var currentScope;
185
+ function getCurrentScope() {
186
+ return currentScope;
187
+ }
188
+ function createScope(parent_, immer_) {
189
+ return {
190
+ drafts_: [],
191
+ parent_,
192
+ immer_,
193
+ canAutoFreeze_: true,
194
+ unfinalizedDrafts_: 0
195
+ };
196
+ }
197
+ function usePatchesInScope(scope, patchListener) {
198
+ if (patchListener) {
199
+ getPlugin("Patches");
200
+ scope.patches_ = [];
201
+ scope.inversePatches_ = [];
202
+ scope.patchListener_ = patchListener;
203
+ }
204
+ }
205
+ function revokeScope(scope) {
206
+ leaveScope(scope);
207
+ scope.drafts_.forEach(revokeDraft);
208
+ scope.drafts_ = null;
209
+ }
210
+ function leaveScope(scope) {
211
+ if (scope === currentScope) currentScope = scope.parent_;
212
+ }
213
+ function enterScope(immer2) {
214
+ return currentScope = createScope(currentScope, immer2);
215
+ }
216
+ function revokeDraft(draft) {
217
+ const state = draft[DRAFT_STATE];
218
+ if (state.type_ === 0 || state.type_ === 1) state.revoke_();
219
+ else state.revoked_ = true;
220
+ }
221
+ function processResult(result, scope) {
222
+ scope.unfinalizedDrafts_ = scope.drafts_.length;
223
+ const baseDraft = scope.drafts_[0];
224
+ if (result !== void 0 && result !== baseDraft) {
225
+ if (baseDraft[DRAFT_STATE].modified_) {
226
+ revokeScope(scope);
227
+ die(4);
228
+ }
229
+ if (isDraftable(result)) {
230
+ result = finalize(scope, result);
231
+ if (!scope.parent_) maybeFreeze(scope, result);
232
+ }
233
+ if (scope.patches_) getPlugin("Patches").generateReplacementPatches_(baseDraft[DRAFT_STATE].base_, result, scope.patches_, scope.inversePatches_);
234
+ } else result = finalize(scope, baseDraft, []);
235
+ revokeScope(scope);
236
+ if (scope.patches_) scope.patchListener_(scope.patches_, scope.inversePatches_);
237
+ return result !== NOTHING ? result : void 0;
238
+ }
239
+ function finalize(rootScope, value, path) {
240
+ if (isFrozen(value)) return value;
241
+ const useStrictIteration = rootScope.immer_.shouldUseStrictIteration();
242
+ const state = value[DRAFT_STATE];
243
+ if (!state) {
244
+ each(value, (key, childValue) => finalizeProperty(rootScope, state, value, key, childValue, path), useStrictIteration);
245
+ return value;
246
+ }
247
+ if (state.scope_ !== rootScope) return value;
248
+ if (!state.modified_) {
249
+ maybeFreeze(rootScope, state.base_, true);
250
+ return state.base_;
251
+ }
252
+ if (!state.finalized_) {
253
+ state.finalized_ = true;
254
+ state.scope_.unfinalizedDrafts_--;
255
+ const result = state.copy_;
256
+ let resultEach = result;
257
+ let isSet2 = false;
258
+ if (state.type_ === 3) {
259
+ resultEach = new Set(result);
260
+ result.clear();
261
+ isSet2 = true;
262
+ }
263
+ each(resultEach, (key, childValue) => finalizeProperty(rootScope, state, result, key, childValue, path, isSet2), useStrictIteration);
264
+ maybeFreeze(rootScope, result, false);
265
+ if (path && rootScope.patches_) getPlugin("Patches").generatePatches_(state, path, rootScope.patches_, rootScope.inversePatches_);
266
+ }
267
+ return state.copy_;
268
+ }
269
+ function finalizeProperty(rootScope, parentState, targetObject, prop, childValue, rootPath, targetIsSet) {
270
+ if (childValue == null) return;
271
+ if (typeof childValue !== "object" && !targetIsSet) return;
272
+ const childIsFrozen = isFrozen(childValue);
273
+ if (childIsFrozen && !targetIsSet) return;
274
+ if (isDraft(childValue)) {
275
+ const res = finalize(rootScope, childValue, rootPath && parentState && parentState.type_ !== 3 && !has(parentState.assigned_, prop) ? rootPath.concat(prop) : void 0);
276
+ set(targetObject, prop, res);
277
+ if (isDraft(res)) rootScope.canAutoFreeze_ = false;
278
+ else return;
279
+ } else if (targetIsSet) targetObject.add(childValue);
280
+ if (isDraftable(childValue) && !childIsFrozen) {
281
+ if (!rootScope.immer_.autoFreeze_ && rootScope.unfinalizedDrafts_ < 1) return;
282
+ if (parentState && parentState.base_ && parentState.base_[prop] === childValue && childIsFrozen) return;
283
+ finalize(rootScope, childValue);
284
+ if ((!parentState || !parentState.scope_.parent_) && typeof prop !== "symbol" && (isMap(targetObject) ? targetObject.has(prop) : Object.prototype.propertyIsEnumerable.call(targetObject, prop))) maybeFreeze(rootScope, childValue);
285
+ }
286
+ }
287
+ function maybeFreeze(scope, value, deep = false) {
288
+ if (!scope.parent_ && scope.immer_.autoFreeze_ && scope.canAutoFreeze_) freeze(value, deep);
289
+ }
290
+ function createProxyProxy(base, parent) {
291
+ const isArray = Array.isArray(base);
292
+ const state = {
293
+ type_: isArray ? 1 : 0,
294
+ scope_: parent ? parent.scope_ : getCurrentScope(),
295
+ modified_: false,
296
+ finalized_: false,
297
+ assigned_: {},
298
+ parent_: parent,
299
+ base_: base,
300
+ draft_: null,
301
+ copy_: null,
302
+ revoke_: null,
303
+ isManual_: false
304
+ };
305
+ let target = state;
306
+ let traps = objectTraps;
307
+ if (isArray) {
308
+ target = [state];
309
+ traps = arrayTraps;
310
+ }
311
+ const { revoke, proxy } = Proxy.revocable(target, traps);
312
+ state.draft_ = proxy;
313
+ state.revoke_ = revoke;
314
+ return proxy;
315
+ }
316
+ var objectTraps = {
317
+ get(state, prop) {
318
+ if (prop === DRAFT_STATE) return state;
319
+ const source = latest(state);
320
+ if (!has(source, prop)) return readPropFromProto(state, source, prop);
321
+ const value = source[prop];
322
+ if (state.finalized_ || !isDraftable(value)) return value;
323
+ if (value === peek(state.base_, prop)) {
324
+ prepareCopy(state);
325
+ return state.copy_[prop] = createProxy(value, state);
326
+ }
327
+ return value;
328
+ },
329
+ has(state, prop) {
330
+ return prop in latest(state);
331
+ },
332
+ ownKeys(state) {
333
+ return Reflect.ownKeys(latest(state));
334
+ },
335
+ set(state, prop, value) {
336
+ const desc = getDescriptorFromProto(latest(state), prop);
337
+ if (desc?.set) {
338
+ desc.set.call(state.draft_, value);
339
+ return true;
340
+ }
341
+ if (!state.modified_) {
342
+ const current2 = peek(latest(state), prop);
343
+ const currentState = current2?.[DRAFT_STATE];
344
+ if (currentState && currentState.base_ === value) {
345
+ state.copy_[prop] = value;
346
+ state.assigned_[prop] = false;
347
+ return true;
348
+ }
349
+ if (is(value, current2) && (value !== void 0 || has(state.base_, prop))) return true;
350
+ prepareCopy(state);
351
+ markChanged(state);
352
+ }
353
+ if (state.copy_[prop] === value && (value !== void 0 || prop in state.copy_) || Number.isNaN(value) && Number.isNaN(state.copy_[prop])) return true;
354
+ state.copy_[prop] = value;
355
+ state.assigned_[prop] = true;
356
+ return true;
357
+ },
358
+ deleteProperty(state, prop) {
359
+ if (peek(state.base_, prop) !== void 0 || prop in state.base_) {
360
+ state.assigned_[prop] = false;
361
+ prepareCopy(state);
362
+ markChanged(state);
363
+ } else delete state.assigned_[prop];
364
+ if (state.copy_) delete state.copy_[prop];
365
+ return true;
366
+ },
367
+ getOwnPropertyDescriptor(state, prop) {
368
+ const owner = latest(state);
369
+ const desc = Reflect.getOwnPropertyDescriptor(owner, prop);
370
+ if (!desc) return desc;
371
+ return {
372
+ writable: true,
373
+ configurable: state.type_ !== 1 || prop !== "length",
374
+ enumerable: desc.enumerable,
375
+ value: owner[prop]
376
+ };
377
+ },
378
+ defineProperty() {
379
+ die(11);
380
+ },
381
+ getPrototypeOf(state) {
382
+ return getPrototypeOf(state.base_);
383
+ },
384
+ setPrototypeOf() {
385
+ die(12);
386
+ }
387
+ };
388
+ var arrayTraps = {};
389
+ each(objectTraps, (key, fn) => {
390
+ arrayTraps[key] = function() {
391
+ arguments[0] = arguments[0][0];
392
+ return fn.apply(this, arguments);
393
+ };
394
+ });
395
+ arrayTraps.deleteProperty = function(state, prop) {
396
+ return arrayTraps.set.call(this, state, prop, void 0);
397
+ };
398
+ arrayTraps.set = function(state, prop, value) {
399
+ return objectTraps.set.call(this, state[0], prop, value, state[0]);
400
+ };
401
+ function peek(draft, prop) {
402
+ const state = draft[DRAFT_STATE];
403
+ return (state ? latest(state) : draft)[prop];
404
+ }
405
+ function readPropFromProto(state, source, prop) {
406
+ const desc = getDescriptorFromProto(source, prop);
407
+ return desc ? `value` in desc ? desc.value : desc.get?.call(state.draft_) : void 0;
408
+ }
409
+ function getDescriptorFromProto(source, prop) {
410
+ if (!(prop in source)) return void 0;
411
+ let proto = getPrototypeOf(source);
412
+ while (proto) {
413
+ const desc = Object.getOwnPropertyDescriptor(proto, prop);
414
+ if (desc) return desc;
415
+ proto = getPrototypeOf(proto);
416
+ }
417
+ }
418
+ function markChanged(state) {
419
+ if (!state.modified_) {
420
+ state.modified_ = true;
421
+ if (state.parent_) markChanged(state.parent_);
422
+ }
423
+ }
424
+ function prepareCopy(state) {
425
+ if (!state.copy_) state.copy_ = shallowCopy(state.base_, state.scope_.immer_.useStrictShallowCopy_);
426
+ }
427
+ var Immer2 = class {
428
+ constructor(config) {
429
+ this.autoFreeze_ = true;
430
+ this.useStrictShallowCopy_ = false;
431
+ this.useStrictIteration_ = true;
432
+ /**
433
+ * The `produce` function takes a value and a "recipe function" (whose
434
+ * return value often depends on the base state). The recipe function is
435
+ * free to mutate its first argument however it wants. All mutations are
436
+ * only ever applied to a __copy__ of the base state.
437
+ *
438
+ * Pass only a function to create a "curried producer" which relieves you
439
+ * from passing the recipe function every time.
440
+ *
441
+ * Only plain objects and arrays are made mutable. All other objects are
442
+ * considered uncopyable.
443
+ *
444
+ * Note: This function is __bound__ to its `Immer` instance.
445
+ *
446
+ * @param {any} base - the initial state
447
+ * @param {Function} recipe - function that receives a proxy of the base state as first argument and which can be freely modified
448
+ * @param {Function} patchListener - optional function that will be called with all the patches produced here
449
+ * @returns {any} a new state, or the initial state if nothing was modified
450
+ */
451
+ this.produce = (base, recipe, patchListener) => {
452
+ if (typeof base === "function" && typeof recipe !== "function") {
453
+ const defaultBase = recipe;
454
+ recipe = base;
455
+ const self = this;
456
+ return function curriedProduce(base2 = defaultBase, ...args) {
457
+ return self.produce(base2, (draft) => recipe.call(this, draft, ...args));
458
+ };
459
+ }
460
+ if (typeof recipe !== "function") die(6);
461
+ if (patchListener !== void 0 && typeof patchListener !== "function") die(7);
462
+ let result;
463
+ if (isDraftable(base)) {
464
+ const scope = enterScope(this);
465
+ const proxy = createProxy(base, void 0);
466
+ let hasError = true;
467
+ try {
468
+ result = recipe(proxy);
469
+ hasError = false;
470
+ } finally {
471
+ if (hasError) revokeScope(scope);
472
+ else leaveScope(scope);
473
+ }
474
+ usePatchesInScope(scope, patchListener);
475
+ return processResult(result, scope);
476
+ } else if (!base || typeof base !== "object") {
477
+ result = recipe(base);
478
+ if (result === void 0) result = base;
479
+ if (result === NOTHING) result = void 0;
480
+ if (this.autoFreeze_) freeze(result, true);
481
+ if (patchListener) {
482
+ const p = [];
483
+ const ip = [];
484
+ getPlugin("Patches").generateReplacementPatches_(base, result, p, ip);
485
+ patchListener(p, ip);
486
+ }
487
+ return result;
488
+ } else die(1, base);
489
+ };
490
+ this.produceWithPatches = (base, recipe) => {
491
+ if (typeof base === "function") return (state, ...args) => this.produceWithPatches(state, (draft) => base(draft, ...args));
492
+ let patches, inversePatches;
493
+ return [
494
+ this.produce(base, recipe, (p, ip) => {
495
+ patches = p;
496
+ inversePatches = ip;
497
+ }),
498
+ patches,
499
+ inversePatches
500
+ ];
501
+ };
502
+ if (typeof config?.autoFreeze === "boolean") this.setAutoFreeze(config.autoFreeze);
503
+ if (typeof config?.useStrictShallowCopy === "boolean") this.setUseStrictShallowCopy(config.useStrictShallowCopy);
504
+ if (typeof config?.useStrictIteration === "boolean") this.setUseStrictIteration(config.useStrictIteration);
505
+ }
506
+ createDraft(base) {
507
+ if (!isDraftable(base)) die(8);
508
+ if (isDraft(base)) base = current(base);
509
+ const scope = enterScope(this);
510
+ const proxy = createProxy(base, void 0);
511
+ proxy[DRAFT_STATE].isManual_ = true;
512
+ leaveScope(scope);
513
+ return proxy;
514
+ }
515
+ finishDraft(draft, patchListener) {
516
+ const state = draft && draft[DRAFT_STATE];
517
+ if (!state || !state.isManual_) die(9);
518
+ const { scope_: scope } = state;
519
+ usePatchesInScope(scope, patchListener);
520
+ return processResult(void 0, scope);
521
+ }
522
+ /**
523
+ * Pass true to automatically freeze all copies created by Immer.
524
+ *
525
+ * By default, auto-freezing is enabled.
526
+ */
527
+ setAutoFreeze(value) {
528
+ this.autoFreeze_ = value;
529
+ }
530
+ /**
531
+ * Pass true to enable strict shallow copy.
532
+ *
533
+ * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
534
+ */
535
+ setUseStrictShallowCopy(value) {
536
+ this.useStrictShallowCopy_ = value;
537
+ }
538
+ /**
539
+ * Pass false to use faster iteration that skips non-enumerable properties
540
+ * but still handles symbols for compatibility.
541
+ *
542
+ * By default, strict iteration is enabled (includes all own properties).
543
+ */
544
+ setUseStrictIteration(value) {
545
+ this.useStrictIteration_ = value;
546
+ }
547
+ shouldUseStrictIteration() {
548
+ return this.useStrictIteration_;
549
+ }
550
+ applyPatches(base, patches) {
551
+ let i;
552
+ for (i = patches.length - 1; i >= 0; i--) {
553
+ const patch = patches[i];
554
+ if (patch.path.length === 0 && patch.op === "replace") {
555
+ base = patch.value;
556
+ break;
557
+ }
558
+ }
559
+ if (i > -1) patches = patches.slice(i + 1);
560
+ const applyPatchesImpl = getPlugin("Patches").applyPatches_;
561
+ if (isDraft(base)) return applyPatchesImpl(base, patches);
562
+ return this.produce(base, (draft) => applyPatchesImpl(draft, patches));
563
+ }
564
+ };
565
+ function createProxy(value, parent) {
566
+ const draft = isMap(value) ? getPlugin("MapSet").proxyMap_(value, parent) : isSet(value) ? getPlugin("MapSet").proxySet_(value, parent) : createProxyProxy(value, parent);
567
+ (parent ? parent.scope_ : getCurrentScope()).drafts_.push(draft);
568
+ return draft;
569
+ }
570
+ function current(value) {
571
+ if (!isDraft(value)) die(10, value);
572
+ return currentImpl(value);
573
+ }
574
+ function currentImpl(value) {
575
+ if (!isDraftable(value) || isFrozen(value)) return value;
576
+ const state = value[DRAFT_STATE];
577
+ let copy;
578
+ let strict = true;
579
+ if (state) {
580
+ if (!state.modified_) return state.base_;
581
+ state.finalized_ = true;
582
+ copy = shallowCopy(value, state.scope_.immer_.useStrictShallowCopy_);
583
+ strict = state.scope_.immer_.shouldUseStrictIteration();
584
+ } else copy = shallowCopy(value, true);
585
+ each(copy, (key, childValue) => {
586
+ set(copy, key, currentImpl(childValue));
587
+ }, strict);
588
+ if (state) state.finalized_ = false;
589
+ return copy;
590
+ }
591
+ var produce = new Immer2().produce;
592
+ //#endregion
593
+ //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-client-store@0.1.2-rc.1_@deepseek-ai+cordis@4.0.1_@types+react@18.3.31_react@18.3.1/node_modules/@deepseek-ai/dsh-client-store/lib/index.js
594
+ /**
595
+ * React-free snapshot store engine (zustand vanilla + immer + subscribeWithSelector +
596
+ * rafFlush middleware + opt-in persist + dev freeze) plus the declarative
597
+ * shell over it: {@link defineStore} bakes an init/persist/actions literal
598
+ * into a {@link StoreHandle}, the registration-side store seat of slot
599
+ * terminals. Engine products are bare observables — subscribe/getSnapshot/
600
+ * update/set, NO selector hook. Hook synthesis is ui-renderer's (the one
601
+ * uSES bridge, cached per source at the binding site).
602
+ */
603
+ /**
604
+ * Notify an observer set without allowing one callback to starve the rest.
605
+ * @param listeners - current observer callbacks; copied before dispatch.
606
+ * @param label - diagnostic owner prefix.
607
+ * @param args - callback arguments.
608
+ */
609
+ function notifySubscribers(listeners, label, ...args) {
610
+ for (const listener of [...listeners]) try {
611
+ listener(...args);
612
+ } catch (error) {
613
+ console.error(`${label} subscriber failed:`, error);
614
+ }
615
+ }
616
+ /** Batches subscriber notification into one flush per animation frame. */
617
+ function rafBatch(notify) {
618
+ const schedule = typeof requestAnimationFrame === "function" ? (fn) => {
619
+ requestAnimationFrame(() => {
620
+ fn();
621
+ });
622
+ } : (fn) => {
623
+ queueMicrotask(fn);
624
+ };
625
+ let scheduled = false;
626
+ return () => {
627
+ if (scheduled) return;
628
+ scheduled = true;
629
+ schedule(() => {
630
+ scheduled = false;
631
+ notify();
632
+ });
633
+ };
634
+ }
635
+ /**
636
+ * Create a snapshot store.
637
+ *
638
+ * Flush default is 'sync' (controlled inputs need same-tick echo); frame-driven
639
+ * stores opt into 'raf', where a frame's worth of updates coalesces into one
640
+ * notification. Known raf-mode tradeoff: a component mounting mid-frame reads
641
+ * fresh state while existing subscribers hear it next flush — transient
642
+ * frame-level skew, same nature as the object layer's microtask batching.
643
+ *
644
+ * @param init - initial state.
645
+ * @param opts - flush mode and opt-in persistence (localStorage, keyed by name).
646
+ * @returns the store.
647
+ */
648
+ function createSnapshotStore(init, opts) {
649
+ const withSelector = subscribeWithSelector(() => init);
650
+ const api = createStore()(withSelector);
651
+ if (opts?.persist) attachPersistence(api, opts.persist.name);
652
+ let subscribe = (fn) => api.subscribe(() => {
653
+ notifySubscribers([fn], "[client-store]");
654
+ });
655
+ if (opts?.flush === "raf") {
656
+ const listeners = /* @__PURE__ */ new Set();
657
+ const flush = rafBatch(() => {
658
+ notifySubscribers(listeners, "[client-store]");
659
+ });
660
+ api.subscribe(flush);
661
+ subscribe = (fn) => {
662
+ listeners.add(fn);
663
+ return () => {
664
+ listeners.delete(fn);
665
+ };
666
+ };
667
+ }
668
+ return {
669
+ getSnapshot: () => api.getState(),
670
+ subscribe: (fn) => subscribe(fn),
671
+ update: (mutator) => {
672
+ api.setState(produce(api.getState(), (draft) => {
673
+ mutator(draft);
674
+ }), true);
675
+ },
676
+ set: (next) => {
677
+ api.setState(devFreeze(next), true);
678
+ }
679
+ };
680
+ }
681
+ /**
682
+ * Whole-value JSON persistence to localStorage. Hand-rolled instead of the
683
+ * zustand persist middleware: its write path spreads state into an object
684
+ * (`partialize({ ...get() })`), exploding primitive state (a persisted string
685
+ * draft becomes {0:'h',1:'e',...}) — not fixable via merge/deserialize options
686
+ * because the corruption happens before serialization. Storage failures
687
+ * (quota, private mode) only disable persistence, never break the store.
688
+ */
689
+ function attachPersistence(api, name) {
690
+ if (typeof localStorage === "undefined") return;
691
+ try {
692
+ const raw = localStorage.getItem(name);
693
+ if (raw !== null) api.setState(devFreeze(JSON.parse(raw)), true);
694
+ } catch (error) {
695
+ console.error(`snapshot store '${name}' rehydration failed:`, error);
696
+ }
697
+ api.subscribe((state) => {
698
+ try {
699
+ localStorage.setItem(name, JSON.stringify(state));
700
+ } catch (error) {
701
+ console.error(`snapshot store '${name}' persistence failed:`, error);
702
+ }
703
+ });
704
+ }
705
+ /** Deep-freeze draftable wholesale-set state outside production: set() bypasses immer's freeze. */
706
+ function devFreeze(value) {
707
+ return freeze(value, true);
708
+ }
709
+ /**
710
+ * Declare a store: initial state, optional persistence, and the full write
711
+ * set as pure draft mutators. The returned handle is the registration
712
+ * currency of the store seat — its identity keys instance sharing. Satisfies
713
+ * ui-slots' DefineStore contract (the handle/instance are the engine-extended
714
+ * subtypes).
715
+ *
716
+ * The `A & ActionsDecl<T>` actions position is load-bearing: T resolves from
717
+ * `init` in the first inference round, and the intersection then contextually
718
+ * types each mutator's draft parameter (context-sensitive functions defer),
719
+ * so call sites write `(d, x: X) => { ... }` with no draft annotation. If a
720
+ * future TS version breaks this single-literal inference, the design's
721
+ * documented fallback is currying (`defineStore(init).actions({...})`).
722
+ * @param decl - init lambda (fresh state per instance), optional persist key, actions table.
723
+ * @returns the store handle.
724
+ */
725
+ function defineStore(decl) {
726
+ return {
727
+ spec: decl,
728
+ create(scopeKey) {
729
+ const persistKey = decl.persist === void 0 ? void 0 : scopeKey === void 0 ? decl.persist : `${decl.persist}.${scopeKey}`;
730
+ const store = createSnapshotStore(decl.init(), persistKey !== void 0 ? { persist: { name: persistKey } } : void 0);
731
+ const actions = {};
732
+ for (const key of Object.keys(decl.actions)) {
733
+ const mutate = decl.actions[key];
734
+ actions[key] = (...params) => {
735
+ store.update((draft) => {
736
+ mutate(draft, ...params);
737
+ });
738
+ };
739
+ }
740
+ return {
741
+ actions,
742
+ getSnapshot: () => store.getSnapshot(),
743
+ subscribe: (fn) => store.subscribe(fn),
744
+ store,
745
+ clearPersisted: () => {
746
+ if (persistKey === void 0 || typeof localStorage === "undefined") return;
747
+ try {
748
+ localStorage.removeItem(persistKey);
749
+ } catch {}
750
+ }
751
+ };
752
+ }
753
+ };
754
+ }
755
+ //#endregion
11
756
  //#region lib/client/locales.js
12
757
  const WORKTREE_NS = "worktree";
13
758
  const zh = {
@@ -426,7 +1171,7 @@ window.__ModuleLoader__.load({
426
1171
  };
427
1172
  }
428
1173
  //#endregion
429
- //#region \0clutch-dsh-worktree-css:/Users/yuancheng/.dsh/clutch-dsh-worktree/worktree/wt_4ab905d8-c228-470f-9208-36c3552257a4/packages/clutch-dsh-worktree/src/client/worktree-context.css.mjs
1174
+ //#region \0clutch-dsh-worktree-css:/Users/yuancheng/.dsh/clutch-dsh-worktree/worktree/wt_6995a053-1215-47ed-b5a3-53a7525317f1/packages/clutch-dsh-worktree/src/client/worktree-context.css.mjs
430
1175
  const css$1 = ".-cerbur-clutch-dsh-worktree-headerContext {\n display: inline-flex;\n min-width: 0;\n height: 22px;\n align-items: center;\n gap: 4px;\n max-width: 180px;\n overflow: hidden;\n border-radius: 6px;\n padding: 0 2px 0 0;\n background: var(--dsw-alias-fill-tsp-secondary);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n line-height: 22px;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-contextIcon {\n flex: none;\n opacity: 0.7;\n}\n\n.-cerbur-clutch-dsh-worktree-contextLabel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-contextHoverTitle {\n max-width: 360px;\n color: var(--dsw-static-neutral-bluish-00);\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: anywhere;\n white-space: normal;\n}\n\n.-cerbur-clutch-dsh-worktree-heroContextHost {\n position: absolute;\n z-index: 1;\n display: block;\n width: max-content;\n max-width: 260px;\n min-height: 22px;\n}\n\n.-cerbur-clutch-dsh-worktree-heroContext {\n display: inline-flex;\n box-sizing: border-box;\n max-width: 260px;\n min-height: 22px;\n align-items: center;\n overflow: hidden;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n padding: 0 8px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n line-height: 20px;\n pointer-events: auto;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n";
431
1176
  const styleId$1 = "@cerbur/clutch-dsh-worktree/worktree-context.css";
432
1177
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree-context.css\"]") === null) {
@@ -467,7 +1212,9 @@ window.__ModuleLoader__.load({
467
1212
  className: worktree_context_css_default.contextHoverTitle,
468
1213
  children: value.label
469
1214
  }),
470
- openDelayMs: 500
1215
+ openDelayMs: 500,
1216
+ copyLabel: t("copy"),
1217
+ copiedLabel: t("hover.copied")
471
1218
  });
472
1219
  }
473
1220
  /** Render the current branch or active Worktree branch beside the Session title. */
@@ -480,7 +1227,7 @@ window.__ModuleLoader__.load({
480
1227
  });
481
1228
  }
482
1229
  //#endregion
483
- //#region \0clutch-dsh-worktree-css:/Users/yuancheng/.dsh/clutch-dsh-worktree/worktree/wt_4ab905d8-c228-470f-9208-36c3552257a4/packages/clutch-dsh-worktree/src/client/worktree.css.mjs
1230
+ //#region \0clutch-dsh-worktree-css:/Users/yuancheng/.dsh/clutch-dsh-worktree/worktree/wt_6995a053-1215-47ed-b5a3-53a7525317f1/packages/clutch-dsh-worktree/src/client/worktree.css.mjs
484
1231
  const css = ".-cerbur-clutch-dsh-worktree-action {\n display: flex;\n align-items: center;\n justify-content: flex-start;\n gap: 8px;\n width: calc(100% + 4px);\n height: 42px;\n margin: 4px -2px;\n box-sizing: border-box;\n border: 0;\n border-radius: 12px;\n padding: 0 10px 0 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n text-align: left;\n overflow: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-action:hover,\n.-cerbur-clutch-dsh-worktree-action[data-active='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-action[data-collapsed='true'] {\n width: 36px;\n height: 36px;\n margin: 8px 0 10px;\n justify-content: center;\n gap: 0;\n padding: 0;\n border-radius: 50%;\n}\n\n.-cerbur-clutch-dsh-worktree-actionLabel {\n display: inline-flex;\n min-width: 0;\n align-items: center;\n height: 22px;\n overflow: hidden;\n font-weight: 400;\n line-height: 22px;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-surface {\n position: absolute;\n top: 0;\n left: 0;\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n min-width: 56px;\n overflow: hidden;\n border-right: 1px solid var(--dsw-alias-border-l1);\n background: var(--dsw-specific-sidebar-fill);\n color: var(--dsw-alias-label-primary);\n pointer-events: auto;\n transition: width var(--ds-transition-duration-slow) var(--ds-ease-in-out);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .-cerbur-clutch-dsh-worktree-surface {\n transition: none;\n }\n}\n\n.-cerbur-clutch-dsh-worktree-wideContent {\n display: flex;\n min-width: 0;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n}\n\n.-cerbur-clutch-dsh-worktree-surface[data-collapsed='true'] .-cerbur-clutch-dsh-worktree-wideContent {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeModalTabs {\n display: flex;\n gap: 8px;\n margin-bottom: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeModalTab {\n border: 0;\n border-bottom: 2px solid transparent;\n padding: 4px 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeModalTab[aria-selected='true'] {\n border-bottom-color: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportCandidates {\n display: grid;\n gap: 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportSelect {\n width: 100%;\n min-width: 0;\n padding: 7px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 13px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeImportError {\n display: grid;\n gap: 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-closeButton {\n border: 0;\n border-radius: 8px;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n\n.-cerbur-clutch-dsh-worktree-closeButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-header {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: none;\n min-height: 44px;\n padding: 6px 10px;\n box-sizing: border-box;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-title {\n min-width: 0;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-closeButton {\n flex: none;\n width: 28px;\n height: 28px;\n font-size: 18px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-modeButton[data-active='true'] {\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspacePicker {\n display: block;\n width: calc(100% - 20px);\n margin: 6px 10px 8px;\n padding: 6px 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceLabel {\n display: block;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-content {\n min-height: 0;\n flex: 1;\n overflow: auto;\n padding: 0 10px 12px;\n}\n\n.-cerbur-clutch-dsh-worktree-content:focus-visible {\n outline: 2px solid var(--dsw-alias-border-l3);\n outline-offset: -2px;\n}\n\n.-cerbur-clutch-dsh-worktree-error {\n margin: 12px 0 0;\n padding: 8px;\n border: 1px solid var(--dsw-alias-state-error-primary);\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-notice {\n margin: 12px 0 0;\n padding: 8px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton,\n.-cerbur-clutch-dsh-worktree-actionButton {\n border: 0;\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton,\n.-cerbur-clutch-dsh-worktree-actionButton {\n width: 100%;\n padding: 6px 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-recoveryActions {\n display: grid;\n gap: 6px;\n margin-top: 6px;\n}\n\n.-cerbur-clutch-dsh-worktree-retryButton:disabled,\n.-cerbur-clutch-dsh-worktree-actionButton:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.-cerbur-clutch-dsh-worktree-actions {\n display: grid;\n gap: 6px;\n margin-top: 10px;\n padding: 8px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-actionSelect {\n min-width: 0;\n padding: 5px 6px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-section {\n margin: 12px 0 0;\n}\n\n.-cerbur-clutch-dsh-worktree-sectionTitle {\n margin: 0 2px 4px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-empty,\n.-cerbur-clutch-dsh-worktree-message {\n margin: 0;\n padding: 8px 4px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 12px;\n line-height: 18px;\n}\n\n.-cerbur-clutch-dsh-worktree-gitReadiness {\n display: grid;\n gap: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-commandBlock {\n margin: 6px 0 0;\n padding: 8px;\n overflow-x: auto;\n border-radius: 6px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-secondary);\n font:\n 11px/16px ui-monospace,\n SFMono-Regular,\n Menlo,\n monospace;\n white-space: pre-wrap;\n}\n\n.-cerbur-clutch-dsh-worktree-message[data-error='true'] {\n color: var(--dsw-alias-state-error-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-worktree,\n.-cerbur-clutch-dsh-worktree-session {\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 6px 8px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font: inherit;\n font-size: 12px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-worktree {\n cursor: default;\n}\n\n.-cerbur-clutch-dsh-worktree-session {\n cursor: pointer;\n}\n\n.-cerbur-clutch-dsh-worktree-worktree:hover,\n.-cerbur-clutch-dsh-worktree-session:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeLabel,\n.-cerbur-clutch-dsh-worktree-sessionLabel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.-cerbur-clutch-dsh-worktree-status {\n flex: none;\n margin-left: auto;\n padding-left: 8px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchRow {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 10px 6px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchIcon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput {\n min-width: 0;\n box-sizing: border-box;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 7px;\n background: var(--dsw-alias-button-elevated-fill);\n color: var(--dsw-alias-label-primary);\n font: inherit;\n outline: none;\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput {\n width: 100%;\n padding: 6px 8px;\n font-size: 13px;\n line-height: 18px;\n}\n\n.-cerbur-clutch-dsh-worktree-searchInput:focus,\n.-cerbur-clutch-dsh-worktree-actionSelect:focus,\n.-cerbur-clutch-dsh-worktree-worktreeImportSelect:focus {\n border-color: #3b82f6;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 0;\n border-radius: 7px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 20px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceList {\n min-width: 0;\n min-height: 0;\n display: grid;\n gap: 4px;\n overflow-x: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceGroup {\n min-width: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow,\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n position: relative;\n display: flex;\n align-items: center;\n min-width: 0;\n min-height: 36px;\n box-sizing: border-box;\n border-radius: 8px;\n padding: 3px 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceDisclosure,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-workspaceIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeDisclosure,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeDisclosure {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-worktreeIcon {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton {\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 28px;\n border: 0;\n border-radius: 6px;\n padding: 0;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 17px;\n line-height: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton > svg {\n display: block;\n}\n\n.-cerbur-clutch-dsh-worktree-disclosureButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon,\n.-cerbur-clutch-dsh-worktree-worktreeIcon {\n flex: none;\n width: 24px;\n color: var(--dsw-alias-label-secondary);\n font-size: 20px;\n line-height: 1;\n text-align: center;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeState {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 12px;\n margin-right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceIcon {\n color: var(--dsw-alias-brand-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceTitle,\n.-cerbur-clutch-dsh-worktree-worktreeLabel {\n min-width: 0;\n overflow: hidden;\n flex: 1;\n padding: 0 6px;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-main-group='true'] .-cerbur-clutch-dsh-worktree-worktreeLabel {\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeHoverTitle {\n color: var(--dsw-static-neutral-bluish-00);\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: anywhere;\n}\n\n/* Native Session hover card: full title, relative time, and current status. */\n.-cerbur-clutch-dsh-worktree-sessionHoverContent {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionHoverTitle {\n color: #FFFFFF;\n font-size: 14px;\n line-height: 20px;\n overflow-wrap: break-word;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionHoverTime {\n color: #CFD3D6;\n font-size: 12px;\n line-height: 16px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionHoverStatus {\n display: flex;\n align-items: center;\n gap: 8px;\n color: #ADB2B8;\n font-size: 12px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot,\n.-cerbur-clutch-dsh-worktree-workspaceActions {\n position: relative;\n display: inline-flex;\n flex: 0 0 64px;\n align-items: center;\n justify-content: flex-end;\n width: 64px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-menuAction {\n position: absolute;\n top: 0;\n right: 32px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n position: absolute;\n top: 0;\n right: 0;\n}\n\n.-cerbur-clutch-dsh-worktree-groupActivity {\n position: absolute;\n top: 0;\n right: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n visibility: hidden;\n pointer-events: none;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-groupActivity {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'][data-menu-open='true'] .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'][data-menu-open='true'] .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-groupActivity,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-groupActivity {\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'] .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:hover .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true'][data-menu-open='true']\n .-cerbur-clutch-dsh-worktree-treeActionSlot\n > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true'][data-menu-open='true']\n .-cerbur-clutch-dsh-worktree-treeActionSlot\n > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-group-activity='true']:focus-within .-cerbur-clutch-dsh-worktree-treeActionSlot > .-cerbur-clutch-dsh-worktree-iconButton:last-child {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-menuAction {\n display: inline-flex;\n width: 28px;\n height: 28px;\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-workspaceRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow:hover .-cerbur-clutch-dsh-worktree-menuAction,\n.-cerbur-clutch-dsh-worktree-worktreeRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-menuAction {\n visibility: visible;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-workspaceRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeChildren {\n margin-left: 16px;\n padding: 2px 0 5px 12px;\n border-left: 1px solid var(--dsw-alias-border-l1);\n}\n\n.-cerbur-clutch-dsh-worktree-groupLabel {\n padding: 6px 8px 3px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 10px;\n font-weight: 600;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader {\n display: flex;\n align-items: center;\n min-height: 34px;\n padding-right: 4px;\n}\n\n.-cerbur-clutch-dsh-worktree-groupHeader .-cerbur-clutch-dsh-worktree-groupLabel {\n flex: 1;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeGroup {\n margin-top: 2px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow {\n min-height: 34px;\n}\n\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-worktreeIcon,\n.-cerbur-clutch-dsh-worktree-worktreeRow .-cerbur-clutch-dsh-worktree-disclosureButton {\n width: 22px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow {\n position: relative;\n display: flex;\n align-items: center;\n width: calc(100% - 22px);\n margin-left: 22px;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border-radius: 7px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-session-current='true'] {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-session-current='true'] .-cerbur-clutch-dsh-worktree-treeSessionContent {\n font-weight: 600;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before,\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n position: absolute;\n right: 4px;\n left: 4px;\n height: 2px;\n border-radius: 2px;\n background: var(--dsw-alias-brand-primary);\n content: '';\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropBefore::before {\n top: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow.-cerbur-clutch-dsh-worktree-dropAfter::after {\n bottom: -1px;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent {\n display: flex;\n align-items: center;\n flex: 1;\n width: 0;\n min-width: 0;\n min-height: 31px;\n box-sizing: border-box;\n border: 0;\n border-radius: 7px;\n padding: 4px 4px;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n font: inherit;\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionContent:hover {\n background: transparent;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionTrailing {\n position: relative;\n display: inline-flex;\n flex: 0 0 52px;\n align-items: center;\n justify-content: flex-end;\n width: 52px;\n height: 28px;\n margin-left: auto;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionMeta,\n.-cerbur-clutch-dsh-worktree-rowActions {\n position: absolute;\n inset: 0;\n display: inline-flex;\n align-items: center;\n justify-content: flex-end;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionMeta {\n color: var(--dsw-alias-label-tertiary);\n pointer-events: none;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionStatus {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionTime {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin-right: 4px;\n font-size: 12px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton {\n display: block;\n width: calc(100% - 24px);\n margin: 2px 0 4px 24px;\n padding: 4px 8px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n font-weight: 400;\n line-height: 20px;\n text-align: left;\n}\n\n.-cerbur-clutch-dsh-worktree-sessionOverflowButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n.-cerbur-clutch-dsh-worktree-rowActions {\n display: none;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover .-cerbur-clutch-dsh-worktree-sessionMeta,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-sessionMeta,\n.-cerbur-clutch-dsh-worktree-sessionTrailing:focus-within .-cerbur-clutch-dsh-worktree-sessionMeta {\n visibility: hidden;\n}\n\n.-cerbur-clutch-dsh-worktree-treeSessionRow:hover .-cerbur-clutch-dsh-worktree-rowActions,\n.-cerbur-clutch-dsh-worktree-treeSessionRow[data-menu-open='true'] .-cerbur-clutch-dsh-worktree-rowActions,\n.-cerbur-clutch-dsh-worktree-sessionTrailing:focus-within .-cerbur-clutch-dsh-worktree-rowActions {\n display: inline-flex;\n}\n\n.-cerbur-clutch-dsh-worktree-renameInput {\n width: 100%;\n}\n\n.-cerbur-clutch-dsh-worktree-renameError {\n margin: 8px 0 0;\n color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n line-height: 20px;\n}\n\n.-cerbur-clutch-dsh-worktree-emptyNested {\n margin: 0;\n padding: 4px 8px 5px 28px;\n color: var(--dsw-alias-label-tertiary);\n font-size: 11px;\n}\n\n.-cerbur-clutch-dsh-worktree-modalField {\n display: grid;\n gap: 5px;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n";
485
1232
  const styleId = "@cerbur/clutch-dsh-worktree/worktree.css";
486
1233
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree.css\"]") === null) {
@@ -700,7 +1447,9 @@ window.__ModuleLoader__.load({
700
1447
  className: worktree_context_css_default.contextHoverTitle,
701
1448
  children: label
702
1449
  }),
703
- openDelayMs: 500
1450
+ openDelayMs: 500,
1451
+ copyLabel: t("copy"),
1452
+ copiedLabel: t("hover.copied")
704
1453
  })
705
1454
  });
706
1455
  }
@@ -936,11 +1685,6 @@ window.__ModuleLoader__.load({
936
1685
  const bound = new Set(boundSessionIds);
937
1686
  return sessionIds.filter((sessionId) => !bound.has(sessionId));
938
1687
  }
939
- /**
940
- * Apply a browser-only membership delta to a DSH Workspace list snapshot.
941
- * `previousBindings` are removed first so the same function can also undo a
942
- * projection after a binding is deleted or the plugin is disposed.
943
- */
944
1688
  function projectVirtualWorkspaceMembership(snapshot, previousBindings, nextBindings) {
945
1689
  const previousSessionIds = new Set(previousBindings.map((binding) => binding.sessionId));
946
1690
  const nextByWorkspace = /* @__PURE__ */ new Map();
@@ -965,6 +1709,34 @@ window.__ModuleLoader__.load({
965
1709
  items
966
1710
  };
967
1711
  }
1712
+ function validTimestamp(value) {
1713
+ return typeof value === "number" && Number.isFinite(value);
1714
+ }
1715
+ function createdAtTimestamp(createdAt) {
1716
+ const timestamp = Date.parse(createdAt);
1717
+ return Number.isFinite(timestamp) ? timestamp : void 0;
1718
+ }
1719
+ /**
1720
+ * Derive the most recent Workspace from rc.1 Session/Workspace metadata.
1721
+ * Host order is retained when timestamps tie, so equal activity never causes
1722
+ * the native Workspace order to oscillate.
1723
+ */
1724
+ function deriveRecentWorkspaceId(workspaces, sessionsById) {
1725
+ let recentWorkspaceId;
1726
+ let recentTimestamp = Number.NEGATIVE_INFINITY;
1727
+ for (const workspace of workspaces.items) {
1728
+ let workspaceTimestamp;
1729
+ for (const sessionId of workspace.sessionIds) {
1730
+ const updatedAt = sessionsById[sessionId]?.updatedAt;
1731
+ if (validTimestamp(updatedAt)) workspaceTimestamp = Math.max(workspaceTimestamp ?? updatedAt, updatedAt);
1732
+ }
1733
+ workspaceTimestamp ??= createdAtTimestamp(workspace.createdAt);
1734
+ if (workspaceTimestamp === void 0 || workspaceTimestamp <= recentTimestamp) continue;
1735
+ recentWorkspaceId = workspace.workspaceId;
1736
+ recentTimestamp = workspaceTimestamp;
1737
+ }
1738
+ return recentWorkspaceId;
1739
+ }
968
1740
  //#endregion
969
1741
  //#region lib/client/worktree-error-copy.js
970
1742
  function detail(error, name) {
@@ -1520,6 +2292,15 @@ window.__ModuleLoader__.load({
1520
2292
  merged[index] = nextView;
1521
2293
  return merged;
1522
2294
  }
2295
+ /** Merge explicit Workspace updates while preserving current order and ready references. */
2296
+ function mergeWorktreeViews(existing, workspaceIds, updates) {
2297
+ const byWorkspaceId = new Map(existing.map((view) => [view.workspaceId, view]));
2298
+ for (const update of updates) byWorkspaceId.set(update.workspaceId, update);
2299
+ return [...new Set(workspaceIds)].flatMap((workspaceId) => {
2300
+ const view = byWorkspaceId.get(workspaceId);
2301
+ return view === void 0 ? [] : [view];
2302
+ });
2303
+ }
1523
2304
  /** Reuse the previous ID snapshot when DSH republishes equivalent Workspace items. */
1524
2305
  function stableWorkspaceIds(previous, next) {
1525
2306
  if (previous.length !== next.length) return next;
@@ -1599,6 +2380,65 @@ window.__ModuleLoader__.load({
1599
2380
  error: viewError
1600
2381
  };
1601
2382
  }
2383
+ /** Share complete Workspace reads without allowing stale generations to repopulate the cache. */
2384
+ function createWorktreeViewReader(manager) {
2385
+ const entries = /* @__PURE__ */ new Map();
2386
+ let disposed = false;
2387
+ const entryFor = (workspaceId) => {
2388
+ const current = entries.get(workspaceId);
2389
+ if (current !== void 0) return current;
2390
+ const created = {
2391
+ generation: 0,
2392
+ stale: false
2393
+ };
2394
+ entries.set(workspaceId, created);
2395
+ return created;
2396
+ };
2397
+ const read = (workspaceId) => {
2398
+ if (disposed) return Promise.reject(/* @__PURE__ */ new Error("Worktree view reader disposed"));
2399
+ const entry = entryFor(workspaceId);
2400
+ if (!entry.stale && entry.view !== void 0) return Promise.resolve(entry.view);
2401
+ if (entry.inFlight?.generation === entry.generation) return entry.inFlight.promise;
2402
+ const generation = entry.generation;
2403
+ const promise = loadWorktreeView(manager, workspaceId).then((data) => {
2404
+ const view = {
2405
+ workspaceId,
2406
+ ...data
2407
+ };
2408
+ if (!disposed && entries.get(workspaceId) === entry && entry.generation === generation) {
2409
+ entry.view = view;
2410
+ entry.stale = false;
2411
+ }
2412
+ return view;
2413
+ }).finally(() => {
2414
+ if (entry.inFlight?.promise === promise) entry.inFlight = void 0;
2415
+ });
2416
+ entry.inFlight = {
2417
+ generation,
2418
+ promise
2419
+ };
2420
+ return promise;
2421
+ };
2422
+ return {
2423
+ invalidate(workspaceId) {
2424
+ if (disposed) return;
2425
+ const entry = entryFor(workspaceId);
2426
+ entry.generation += 1;
2427
+ entry.stale = true;
2428
+ entry.view = void 0;
2429
+ },
2430
+ read,
2431
+ readMany(workspaceIds) {
2432
+ const uniqueIds = [...new Set(workspaceIds)];
2433
+ return Promise.all(uniqueIds.map((workspaceId) => read(workspaceId)));
2434
+ },
2435
+ dispose() {
2436
+ if (disposed) return;
2437
+ disposed = true;
2438
+ entries.clear();
2439
+ }
2440
+ };
2441
+ }
1602
2442
  /** Read all three Worktree projections needed by the surface in one refresh. */
1603
2443
  async function loadWorktreeView(manager, workspaceId) {
1604
2444
  const [worktreesResult, branchesResult, bindingsResult] = await Promise.allSettled([
@@ -1625,28 +2465,16 @@ window.__ModuleLoader__.load({
1625
2465
  readiness: branchesResult.value.length > 0 ? { status: "ready" } : { status: "noLocalBranch" }
1626
2466
  };
1627
2467
  }
1628
- /** Isolate modal-target reads from full-surface refresh generations. */
1629
- function createWorktreeModalViewLoader() {
2468
+ /** Isolate modal-target callbacks while sharing the Client Workspace reader. */
2469
+ function createWorktreeModalViewLoader(reader) {
1630
2470
  const guard = createWorktreeRefreshGuard();
1631
2471
  return {
1632
2472
  invalidate: guard.invalidate,
1633
- load(manager, workspaceId, onSuccess, onError) {
1634
- return guard.run(() => loadWorktreeView(manager, workspaceId), (data) => onSuccess({
1635
- workspaceId,
1636
- ...data
1637
- }), (error) => onError(toWorktreeViewError(error)));
2473
+ load(workspaceId, onSuccess, onError) {
2474
+ return guard.run(() => reader.read(workspaceId), onSuccess, (error) => onError(toWorktreeViewError(error)));
1638
2475
  }
1639
2476
  };
1640
2477
  }
1641
- /** Load one independent projection per DSH Workspace for the flat sidebar hierarchy. */
1642
- async function loadWorktreeViews(manager, workspaceIds, options = {}) {
1643
- const views = await Promise.all(workspaceIds.map(async (workspaceId) => ({
1644
- workspaceId,
1645
- ...await loadWorktreeView(manager, workspaceId)
1646
- })));
1647
- if (options.invalidateContext !== false) await options.invalidateWorktreeContext?.();
1648
- return views;
1649
- }
1650
2478
  /** Hide DSH-archived Sessions from the browser-local Worktree projection. */
1651
2479
  function filterArchivedSessionIds(sessionIds, archivedSessionIds) {
1652
2480
  return sessionIds.filter((sessionId) => !archivedSessionIds.includes(sessionId));
@@ -2617,7 +3445,9 @@ window.__ModuleLoader__.load({
2617
3445
  children: label
2618
3446
  }),
2619
3447
  openDelayMs: 500,
2620
- disabled: menu?.open === true
3448
+ disabled: menu?.open === true,
3449
+ copyLabel: t("copy"),
3450
+ copiedLabel: t("hover.copied")
2621
3451
  });
2622
3452
  }
2623
3453
  /** Worktree-mode Session row with the same trailing options menu as native DSH rows. */
@@ -2818,7 +3648,8 @@ window.__ModuleLoader__.load({
2818
3648
  const EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT = () => void 0;
2819
3649
  const EMPTY_FORK_RECOVERY_SNAPSHOT = {
2820
3650
  revision: 0,
2821
- pending: []
3651
+ pending: [],
3652
+ affectedWorkspaceIds: []
2822
3653
  };
2823
3654
  const EMPTY_FORK_RECOVERY_STORE = {
2824
3655
  getSnapshot: () => EMPTY_FORK_RECOVERY_SNAPSHOT,
@@ -2849,7 +3680,7 @@ window.__ModuleLoader__.load({
2849
3680
  * Peer Worktree navigation surface. It keeps the original DSH Workspace mode
2850
3681
  * intact and renders a browser-local Workspace → Worktree → Session projection.
2851
3682
  */
2852
- 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 }) {
3683
+ function WorktreeSurface({ useStore, actions, useSessions, useWorkspaces, t, available, expandState, sessionOrder, manager, viewReader, permission, confirmFullAccess, fullAccessConfirmation, onPermissionResult, onPermissionNotice, permissionNotice, invalidateWorktreeContext, createWorkspace, createSessionForWorktree: createSessionCallback, createMainSession, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, insertSessionBefore, insertWorktreeBefore, renameSession, forkSession, archiveSession, forkRecovery, retryForkSession, ensureSessionWorkspace, syncSessionWorkspaces, openSession }) {
2853
3684
  const mode = effectiveViewMode(useStore((state) => state.viewMode), available && manager !== void 0);
2854
3685
  const sessions = useSessions((state) => state);
2855
3686
  const workspaces = useWorkspaces((state) => state);
@@ -2857,6 +3688,8 @@ window.__ModuleLoader__.load({
2857
3688
  const forkRecoverySnapshot = (0, react.useSyncExternalStore)(forkRecoveryStore.subscribe, forkRecoveryStore.getSnapshot, forkRecoveryStore.getSnapshot);
2858
3689
  const currentSessionId = sessions.current;
2859
3690
  const workspaceIds = useStableWorkspaceIds(workspaces.items);
3691
+ const workspaceIdsRef = (0, react.useRef)(workspaceIds);
3692
+ workspaceIdsRef.current = workspaceIds;
2860
3693
  const [readState, setReadState] = (0, react.useState)(EMPTY_READ_STATE);
2861
3694
  const expandSnapshot = (0, react.useSyncExternalStore)(expandState.subscribe, expandState.getSnapshot, expandState.getSnapshot);
2862
3695
  const permissionNoticeSnapshot = (0, react.useSyncExternalStore)(permissionNotice?.subscribe ?? EMPTY_PERMISSION_NOTICE_SUBSCRIBE, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT);
@@ -2919,8 +3752,9 @@ window.__ModuleLoader__.load({
2919
3752
  const [worktreeDrag, setWorktreeDrag] = (0, react.useState)();
2920
3753
  const worktreeDropCommitted = (0, react.useRef)(false);
2921
3754
  const refreshGuard = (0, react.useRef)(createWorktreeRefreshGuard());
3755
+ const targetRefreshGuards = (0, react.useRef)(/* @__PURE__ */ new Map());
2922
3756
  const forkRecoveryRevisionRef = (0, react.useRef)(forkRecoverySnapshot.revision);
2923
- const modalReadLoader = (0, react.useRef)(createWorktreeModalViewLoader());
3757
+ const modalReadLoader = (0, react.useRef)(createWorktreeModalViewLoader(viewReader));
2924
3758
  const modalReadViewRef = (0, react.useRef)();
2925
3759
  const importCandidatesGuard = (0, react.useRef)(createWorktreeRefreshGuard());
2926
3760
  const modalWorkspaceIdRef = (0, react.useRef)(worktreeModalWorkspaceId);
@@ -2930,37 +3764,112 @@ window.__ModuleLoader__.load({
2930
3764
  const query = searchQuery.trim().toLocaleLowerCase();
2931
3765
  const archivedSessionIds = workspaces.archivedSessionIds ?? [];
2932
3766
  const pendingSessionArchived = pendingSessionBinding !== void 0 && archivedSessionIds.includes(pendingSessionBinding.sessionId);
3767
+ const guardFor = (workspaceId) => {
3768
+ const current = targetRefreshGuards.current.get(workspaceId);
3769
+ if (current !== void 0) return current;
3770
+ const created = createWorktreeRefreshGuard();
3771
+ targetRefreshGuards.current.set(workspaceId, created);
3772
+ return created;
3773
+ };
2933
3774
  const refresh = (0, react.useCallback)(async (options = {}) => {
2934
3775
  if (manager === void 0) {
2935
3776
  refreshGuard.current.invalidate();
3777
+ for (const guard of targetRefreshGuards.current.values()) guard.invalidate();
2936
3778
  setReadState(EMPTY_READ_STATE);
2937
3779
  return;
2938
3780
  }
3781
+ const scope = options.scope ?? { kind: "global" };
2939
3782
  const preserveCurrent = options.preserveCurrent === true;
2940
- if (!preserveCurrent) setReadState({
2941
- status: "loading",
2942
- views: []
2943
- });
2944
- await refreshGuard.current.run(() => loadWorktreeViews(manager, workspaceIds, {
2945
- invalidateContext: options.invalidateContext !== false,
2946
- invalidateWorktreeContext
2947
- }), (views) => {
2948
- setReadState({
2949
- status: "ready",
2950
- views: modalReadViewRef.current === void 0 ? views : mergeWorktreeView(views, modalReadViewRef.current)
3783
+ const currentWorkspaceIds = workspaceIdsRef.current;
3784
+ if (scope.kind === "global") {
3785
+ if (!preserveCurrent) setReadState({
3786
+ status: "loading",
3787
+ views: []
2951
3788
  });
2952
- }, (error) => {
2953
- if (preserveCurrent) throw error;
2954
- setReadState({
2955
- status: "error",
2956
- views: modalReadViewRef.current === void 0 ? [] : [modalReadViewRef.current],
2957
- error: toWorktreeViewError(error)
3789
+ const selectedWorkspaceIds = [...currentWorkspaceIds];
3790
+ for (const workspaceId of selectedWorkspaceIds) viewReader.invalidate(workspaceId);
3791
+ const contextRefresh = options.invalidateContext === false ? void 0 : invalidateWorktreeContext?.();
3792
+ await refreshGuard.current.run(async () => {
3793
+ const [views] = await Promise.all([viewReader.readMany(selectedWorkspaceIds), contextRefresh ?? Promise.resolve()]);
3794
+ return views;
3795
+ }, (views) => {
3796
+ setReadState((current) => {
3797
+ const merged = mergeWorktreeViews(current.views, workspaceIdsRef.current, views);
3798
+ return {
3799
+ status: "ready",
3800
+ views: modalReadViewRef.current === void 0 ? merged : mergeWorktreeView(merged, modalReadViewRef.current)
3801
+ };
3802
+ });
3803
+ }, (error) => {
3804
+ if (preserveCurrent) throw error;
3805
+ setReadState({
3806
+ status: "error",
3807
+ views: modalReadViewRef.current === void 0 ? [] : [modalReadViewRef.current],
3808
+ error: toWorktreeViewError(error)
3809
+ });
2958
3810
  });
2959
- });
3811
+ return;
3812
+ }
3813
+ const requestedWorkspaceIds = scope.kind === "workspace" ? [scope.workspaceId] : scope.workspaceIds;
3814
+ const selectedWorkspaceIds = [...new Set(requestedWorkspaceIds)].filter((workspaceId) => currentWorkspaceIds.includes(workspaceId));
3815
+ if (selectedWorkspaceIds.length === 0) return;
3816
+ await Promise.allSettled(selectedWorkspaceIds.map(async (workspaceId) => {
3817
+ const guard = guardFor(workspaceId);
3818
+ viewReader.invalidate(workspaceId);
3819
+ const contextRefresh = options.invalidateContext === false ? void 0 : invalidateWorktreeContext?.(workspaceId);
3820
+ const generation = guard.begin();
3821
+ try {
3822
+ const view = await viewReader.read(workspaceId);
3823
+ if (!guard.isCurrent(generation)) return;
3824
+ if (!workspaceIdsRef.current.includes(workspaceId)) return;
3825
+ setReadState((current) => {
3826
+ const remainingTargetError = current.targetError?.workspaceIds.filter((candidate) => candidate !== workspaceId) ?? [];
3827
+ const next = {
3828
+ ...current,
3829
+ status: "ready",
3830
+ views: mergeWorktreeViews(current.views, workspaceIdsRef.current, [view]),
3831
+ error: void 0
3832
+ };
3833
+ if (remainingTargetError.length === 0) {
3834
+ const withoutTargetError = { ...next };
3835
+ delete withoutTargetError.targetError;
3836
+ return withoutTargetError;
3837
+ }
3838
+ return {
3839
+ ...next,
3840
+ targetError: {
3841
+ workspaceIds: remainingTargetError,
3842
+ error: current.targetError.error
3843
+ }
3844
+ };
3845
+ });
3846
+ } catch (error) {
3847
+ if (!guard.isCurrent(generation)) return;
3848
+ if (!workspaceIdsRef.current.includes(workspaceId)) return;
3849
+ setReadState((current) => {
3850
+ const previousIds = current.targetError?.workspaceIds ?? [];
3851
+ return {
3852
+ ...current,
3853
+ status: "ready",
3854
+ views: mergeWorktreeViews(current.views, workspaceIdsRef.current, []),
3855
+ error: void 0,
3856
+ targetError: {
3857
+ workspaceIds: [.../* @__PURE__ */ new Set([...previousIds, workspaceId])],
3858
+ error: {
3859
+ ...toWorktreeViewError(error),
3860
+ retryable: true
3861
+ }
3862
+ }
3863
+ };
3864
+ });
3865
+ } finally {
3866
+ await contextRefresh?.catch(() => void 0);
3867
+ }
3868
+ }));
2960
3869
  }, [
2961
3870
  invalidateWorktreeContext,
2962
3871
  manager,
2963
- workspaceIds
3872
+ viewReader
2964
3873
  ]);
2965
3874
  const loadModalWorktreeView = (0, react.useCallback)((workspaceId) => {
2966
3875
  setModalReadError(void 0);
@@ -2974,7 +3883,7 @@ window.__ModuleLoader__.load({
2974
3883
  });
2975
3884
  return;
2976
3885
  }
2977
- modalReadLoader.current.load(manager, workspaceId, (view) => {
3886
+ modalReadLoader.current.load(workspaceId, (view) => {
2978
3887
  modalReadViewRef.current = view;
2979
3888
  setModalReadLoading(false);
2980
3889
  setReadState((current) => ({
@@ -2985,11 +3894,12 @@ window.__ModuleLoader__.load({
2985
3894
  setModalReadLoading(false);
2986
3895
  setModalReadError(toWorktreeViewError(error));
2987
3896
  });
2988
- }, [manager]);
3897
+ }, [manager, viewReader]);
2989
3898
  (0, react.useEffect)(() => {
2990
3899
  if (mode === "worktree") refresh({ preserveCurrent: readStateRef.current.status === "ready" });
2991
3900
  else {
2992
3901
  refreshGuard.current.invalidate();
3902
+ for (const guard of targetRefreshGuards.current.values()) guard.invalidate();
2993
3903
  modalReadLoader.current.invalidate();
2994
3904
  modalReadViewRef.current = void 0;
2995
3905
  setWorktreeModalWorkspaceId(void 0);
@@ -2998,15 +3908,60 @@ window.__ModuleLoader__.load({
2998
3908
  setReadState(EMPTY_READ_STATE);
2999
3909
  }
3000
3910
  }, [mode, refresh]);
3911
+ const previousWorkspaceIdsRef = (0, react.useRef)(workspaceIds);
3912
+ (0, react.useEffect)(() => {
3913
+ const previousWorkspaceIds = previousWorkspaceIdsRef.current;
3914
+ previousWorkspaceIdsRef.current = workspaceIds;
3915
+ if (mode !== "worktree") return;
3916
+ const addedWorkspaceIds = workspaceIds.filter((workspaceId) => !previousWorkspaceIds.includes(workspaceId));
3917
+ const removedWorkspaceIds = previousWorkspaceIds.filter((workspaceId) => !workspaceIds.includes(workspaceId));
3918
+ for (const workspaceId of removedWorkspaceIds) targetRefreshGuards.current.delete(workspaceId);
3919
+ setReadState((current) => {
3920
+ const views = mergeWorktreeViews(current.views, workspaceIds, []);
3921
+ const remainingTargetError = current.targetError?.workspaceIds.filter((workspaceId) => workspaceIds.includes(workspaceId)) ?? [];
3922
+ const next = {
3923
+ ...current,
3924
+ views
3925
+ };
3926
+ if (remainingTargetError.length === 0) {
3927
+ const withoutTargetError = { ...next };
3928
+ delete withoutTargetError.targetError;
3929
+ return withoutTargetError;
3930
+ }
3931
+ return {
3932
+ ...next,
3933
+ targetError: {
3934
+ workspaceIds: remainingTargetError,
3935
+ error: current.targetError.error
3936
+ }
3937
+ };
3938
+ });
3939
+ for (const workspaceId of addedWorkspaceIds) refresh({
3940
+ scope: {
3941
+ kind: "workspace",
3942
+ workspaceId
3943
+ },
3944
+ preserveCurrent: true
3945
+ }).catch(() => {});
3946
+ }, [
3947
+ mode,
3948
+ refresh,
3949
+ workspaceIds
3950
+ ]);
3001
3951
  (0, react.useEffect)(() => {
3002
3952
  if (forkRecoveryRevisionRef.current === forkRecoverySnapshot.revision) return;
3003
3953
  forkRecoveryRevisionRef.current = forkRecoverySnapshot.revision;
3004
3954
  if (mode !== "worktree" || manager === void 0) return;
3955
+ if (forkRecoverySnapshot.affectedWorkspaceIds.length === 0) return;
3005
3956
  refresh({
3006
- preserveCurrent: readStateRef.current.status === "ready",
3007
- invalidateContext: false
3957
+ scope: {
3958
+ kind: "workspaces",
3959
+ workspaceIds: forkRecoverySnapshot.affectedWorkspaceIds
3960
+ },
3961
+ preserveCurrent: readStateRef.current.status === "ready"
3008
3962
  }).catch(() => {});
3009
3963
  }, [
3964
+ forkRecoverySnapshot.affectedWorkspaceIds,
3010
3965
  forkRecoverySnapshot.revision,
3011
3966
  manager,
3012
3967
  mode,
@@ -3149,12 +4104,12 @@ window.__ModuleLoader__.load({
3149
4104
  return createDefaultWorktreeName([...modalView.branches.map((branch) => branch.name), ...modalView.worktrees.map((worktree) => worktree.branch)]);
3150
4105
  });
3151
4106
  }, [modalView, worktreeModalWorkspaceId]);
3152
- const runMutation = async (operation) => {
4107
+ const runMutation = async (operation, refreshOptions) => {
3153
4108
  setActionPending(true);
3154
4109
  setActionError(void 0);
3155
4110
  try {
3156
4111
  await operation();
3157
- await refresh({ preserveCurrent: true });
4112
+ if (refreshOptions !== void 0) await refresh(refreshOptions);
3158
4113
  } catch (error) {
3159
4114
  setActionError(toWorktreeViewError(error));
3160
4115
  } finally {
@@ -3321,6 +4276,10 @@ window.__ModuleLoader__.load({
3321
4276
  }
3322
4277
  setActionError(void 0);
3323
4278
  insertWorktreeBefore(workspaceId, activeDrag.worktreeId, move.beforeWorktreeId).then(() => refresh({
4279
+ scope: {
4280
+ kind: "workspace",
4281
+ workspaceId
4282
+ },
3324
4283
  preserveCurrent: true,
3325
4284
  invalidateContext: false
3326
4285
  })).catch((error) => {
@@ -3477,7 +4436,13 @@ window.__ModuleLoader__.load({
3477
4436
  const continueWorktreeRegistration = async (registeredWorktree) => {
3478
4437
  closeWorktreeCreator(true);
3479
4438
  if (createSessionCallback === void 0) {
3480
- await refresh({ preserveCurrent: true });
4439
+ await refresh({
4440
+ scope: {
4441
+ kind: "workspace",
4442
+ workspaceId: registeredWorktree.workspaceId
4443
+ },
4444
+ preserveCurrent: true
4445
+ });
3481
4446
  setActionError({
3482
4447
  code: "WORKTREE_REGISTRATION_SESSION_UNAVAILABLE",
3483
4448
  message: "",
@@ -3492,7 +4457,6 @@ window.__ModuleLoader__.load({
3492
4457
  };
3493
4458
  try {
3494
4459
  await createSessionCallback(sessionInput);
3495
- await invalidateWorktreeContext?.(registeredWorktree.workspaceId);
3496
4460
  } catch (error) {
3497
4461
  if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
3498
4462
  ...sessionInput,
@@ -3505,7 +4469,13 @@ window.__ModuleLoader__.load({
3505
4469
  });
3506
4470
  throw error;
3507
4471
  }
3508
- await refresh({ preserveCurrent: true });
4472
+ await refresh({
4473
+ scope: {
4474
+ kind: "workspace",
4475
+ workspaceId: registeredWorktree.workspaceId
4476
+ },
4477
+ preserveCurrent: true
4478
+ });
3509
4479
  };
3510
4480
  const submitWorktree = async () => {
3511
4481
  const worktreeName = newBranch.trim();
@@ -3557,8 +4527,13 @@ window.__ModuleLoader__.load({
3557
4527
  setPendingSessionBinding(void 0);
3558
4528
  try {
3559
4529
  await createSessionCallback(input);
3560
- await invalidateWorktreeContext?.(input.workspaceId);
3561
- await refresh({ preserveCurrent: true });
4530
+ await refresh({
4531
+ scope: {
4532
+ kind: "workspace",
4533
+ workspaceId: input.workspaceId
4534
+ },
4535
+ preserveCurrent: true
4536
+ });
3562
4537
  } catch (error) {
3563
4538
  if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
3564
4539
  ...input,
@@ -3593,8 +4568,13 @@ window.__ModuleLoader__.load({
3593
4568
  openSession
3594
4569
  });
3595
4570
  setPendingSessionBinding(void 0);
3596
- await refresh({ preserveCurrent: true });
3597
- await invalidateWorktreeContext?.(pending.workspaceId);
4571
+ await refresh({
4572
+ scope: {
4573
+ kind: "workspace",
4574
+ workspaceId: pending.workspaceId
4575
+ },
4576
+ preserveCurrent: true
4577
+ });
3598
4578
  } catch (error) {
3599
4579
  if (error instanceof WorktreeSessionBindingError && !error.retryable) setPendingSessionBinding(void 0);
3600
4580
  setActionError(toWorktreeViewError(error));
@@ -3765,12 +4745,35 @@ window.__ModuleLoader__.load({
3765
4745
  className: worktree_css_default.retryButton,
3766
4746
  onClick: () => {
3767
4747
  setActionError(void 0);
3768
- refresh();
4748
+ refresh({ scope: { kind: "global" } });
3769
4749
  },
3770
4750
  children: t("action.retry")
3771
4751
  })
3772
4752
  ]
3773
4753
  }),
4754
+ readState.targetError !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
4755
+ className: worktree_css_default.error,
4756
+ role: "alert",
4757
+ "data-worktree-target-error": true,
4758
+ children: [(0, react_jsx_runtime.jsx)("p", {
4759
+ className: worktree_css_default.message,
4760
+ "data-error": "true",
4761
+ children: formatWorktreeViewError(readState.targetError.error, t)
4762
+ }), (0, react_jsx_runtime.jsx)("button", {
4763
+ type: "button",
4764
+ className: worktree_css_default.retryButton,
4765
+ onClick: () => {
4766
+ refresh({
4767
+ scope: {
4768
+ kind: "workspaces",
4769
+ workspaceIds: readState.targetError.workspaceIds
4770
+ },
4771
+ preserveCurrent: true
4772
+ });
4773
+ },
4774
+ children: t("action.retry")
4775
+ })]
4776
+ }),
3774
4777
  readState.status === "loading" && (0, react_jsx_runtime.jsx)("p", {
3775
4778
  className: worktree_css_default.message,
3776
4779
  children: t("status.loading")
@@ -3787,7 +4790,7 @@ window.__ModuleLoader__.load({
3787
4790
  type: "button",
3788
4791
  className: worktree_css_default.retryButton,
3789
4792
  onClick: () => {
3790
- refresh();
4793
+ refresh({ scope: { kind: "global" } });
3791
4794
  },
3792
4795
  children: t("action.retry")
3793
4796
  })]
@@ -4201,8 +5204,13 @@ window.__ModuleLoader__.load({
4201
5204
  mutationToken
4202
5205
  }
4203
5206
  }, permission, onPermissionNotice);
4204
- await invalidateWorktreeContext?.(target.workspaceId);
4205
5207
  setWorktreeRemoval(void 0);
5208
+ }, {
5209
+ scope: {
5210
+ kind: "workspace",
5211
+ workspaceId: target.workspaceId
5212
+ },
5213
+ preserveCurrent: true
4206
5214
  });
4207
5215
  }
4208
5216
  }),
@@ -4212,6 +5220,7 @@ window.__ModuleLoader__.load({
4212
5220
  description: fullAccessConfirmationSnapshot === void 0 ? "" : t("permission.fullAccessDescription", { cwd: fullAccessConfirmationSnapshot.cwd }),
4213
5221
  acknowledgeLabel: t("permission.fullAccessAcknowledge"),
4214
5222
  cancelLabel: t("dialog.cancel"),
5223
+ closeLabel: t("dialog.close"),
4215
5224
  confirmLabel: t("permission.fullAccessEnable"),
4216
5225
  acknowledged: fullAccessAcknowledged,
4217
5226
  onAcknowledgedChange: setFullAccessAcknowledged,
@@ -4287,11 +5296,13 @@ window.__ModuleLoader__.load({
4287
5296
  };
4288
5297
  }
4289
5298
  function identityFrom(sessions, workspaces) {
4290
- const sessionId = sessions.getSnapshot().current;
4291
- if (sessionId === void 0) return { workspaceId: workspaces.getSnapshot().recentWorkspaceId };
5299
+ const sessionSnapshot = sessions.getSnapshot();
5300
+ const workspaceSnapshot = workspaces.getSnapshot();
5301
+ const sessionId = sessionSnapshot.current;
5302
+ if (sessionId === void 0) return { workspaceId: deriveRecentWorkspaceId({ items: workspaceSnapshot.items }, sessionSnapshot.byId) };
4292
5303
  return {
4293
5304
  sessionId,
4294
- workspaceId: workspaces.getSnapshot().items.find((candidate) => candidate.sessionIds.includes(sessionId))?.workspaceId
5305
+ workspaceId: workspaceSnapshot.items.find((candidate) => candidate.sessionIds.includes(sessionId))?.workspaceId
4295
5306
  };
4296
5307
  }
4297
5308
  /**
@@ -4310,7 +5321,6 @@ window.__ModuleLoader__.load({
4310
5321
  let scheduleTicket = 0;
4311
5322
  let scheduledCompletion;
4312
5323
  let latestRefresh = Promise.resolve();
4313
- const viewCache = /* @__PURE__ */ new Map();
4314
5324
  let lastObservedIdentity;
4315
5325
  const sameIdentity = (left, right) => left?.sessionId === right.sessionId && left?.workspaceId === right.workspaceId;
4316
5326
  const workspaceTitleFor = (workspaceId) => input.workspaces.getSnapshot().items.find((candidate) => candidate.workspaceId === workspaceId)?.title;
@@ -4347,14 +5357,15 @@ window.__ModuleLoader__.load({
4347
5357
  });
4348
5358
  return;
4349
5359
  }
4350
- const cachedView = viewCache.get(identity.workspaceId);
4351
- if (cachedView !== void 0) {
5360
+ const current = store.getSnapshot();
5361
+ if (current.status === "ready" && current.workspaceId !== identity.workspaceId) return;
5362
+ if (current.status === "ready" && current.workspaceId === identity.workspaceId) {
4352
5363
  store.set({
4353
5364
  status: "ready",
4354
5365
  ...identity.sessionId === void 0 ? {} : { sessionId: identity.sessionId },
4355
5366
  workspaceId: identity.workspaceId,
4356
5367
  workspaceTitle: workspaceTitleFor(identity.workspaceId),
4357
- value: valueFrom(identity, cachedView)
5368
+ value: current.value
4358
5369
  });
4359
5370
  return;
4360
5371
  }
@@ -4383,7 +5394,7 @@ window.__ModuleLoader__.load({
4383
5394
  workspaceId: identity.workspaceId
4384
5395
  };
4385
5396
  try {
4386
- const data = await loadWorktreeView(input.manager, request.workspaceId);
5397
+ const data = await input.viewReader.read(request.workspaceId);
4387
5398
  if (!matchesCurrent(request, requestGeneration)) return;
4388
5399
  const workspace = input.workspaces.getSnapshot().items.find((candidate) => candidate.workspaceId === request.workspaceId);
4389
5400
  if ("error" in data.readiness) {
@@ -4397,7 +5408,6 @@ window.__ModuleLoader__.load({
4397
5408
  });
4398
5409
  return;
4399
5410
  }
4400
- if (data.readiness.status === "ready") viewCache.set(request.workspaceId, data);
4401
5411
  store.set({
4402
5412
  status: "ready",
4403
5413
  ...request.sessionId === void 0 ? {} : { sessionId: request.sessionId },
@@ -4478,6 +5488,8 @@ window.__ModuleLoader__.load({
4478
5488
  if (disposed) return;
4479
5489
  const identity = identityFrom(input.sessions, input.workspaces);
4480
5490
  if (workspaceId !== void 0 && workspaceId !== identity.workspaceId) return;
5491
+ if (identity.workspaceId === void 0) return;
5492
+ input.viewReader.invalidate(identity.workspaceId);
4481
5493
  await refresh();
4482
5494
  await waitForLatestRefresh(workspaceId ?? identity.workspaceId);
4483
5495
  },
@@ -4488,7 +5500,6 @@ window.__ModuleLoader__.load({
4488
5500
  cancelScheduledRefresh();
4489
5501
  unsubscribeSessions();
4490
5502
  unsubscribeWorkspaces();
4491
- viewCache.clear();
4492
5503
  store.set({
4493
5504
  status: "idle",
4494
5505
  value: notReady()
@@ -4500,7 +5511,7 @@ window.__ModuleLoader__.load({
4500
5511
  //#region lib/client/view-mode-store.js
4501
5512
  /** Create one root-scoped, browser-local view-mode store for the two slot entries. */
4502
5513
  function createWorktreeViewStore() {
4503
- return (0, _deepseek_ai_dsh_client_runtime_client.defineStore)({
5514
+ return defineStore({
4504
5515
  init: () => ({ viewMode: "workspace-session" }),
4505
5516
  persist: WORKTREE_VIEW_MODE_STORAGE_KEY,
4506
5517
  actions: { setViewMode: (draft, mode) => {
@@ -4518,54 +5529,85 @@ window.__ModuleLoader__.load({
4518
5529
  }
4519
5530
  return [...bySession.values()];
4520
5531
  }
4521
- function sameWorkspaceItems(left, right) {
4522
- if (left.items.length !== right.items.length) return false;
4523
- return left.items.every((item, index) => {
4524
- const other = right.items[index];
4525
- if (item === other) return true;
4526
- if (typeof item !== "object" || item === null || typeof other !== "object" || other === null || !("workspaceId" in item) || !("workspaceId" in other) || !("sessionIds" in item) || !("sessionIds" in other)) return false;
4527
- const leftSessionIds = item.sessionIds;
4528
- const rightSessionIds = other.sessionIds;
4529
- return item.workspaceId === other.workspaceId && Array.isArray(leftSessionIds) && Array.isArray(rightSessionIds) && leftSessionIds.length === rightSessionIds.length && leftSessionIds.every((sessionId, sessionIndex) => sessionId === rightSessionIds[sessionIndex]);
5532
+ function sameBindings(left, right) {
5533
+ return left.length === right.length && left.every((binding, index) => {
5534
+ const other = right[index];
5535
+ return binding.workspaceId === other.workspaceId && binding.sessionId === other.sessionId;
4530
5536
  });
4531
5537
  }
4532
5538
  /**
4533
- * Maintains a re-playable in-memory overlay over DSH's Workspace list. Native
4534
- * refreshes are observed and the current sidecar bindings are applied again;
4535
- * no DSH Host mutation or persistence is involved.
5539
+ * Decorate DSH's read-only WorkspaceSource with a browser-local membership
5540
+ * projection. The source's native model is never written: the wrapper keeps
5541
+ * the current sidecar bindings in memory, reprojects every native snapshot,
5542
+ * and publishes only the projected view to subscribers.
4536
5543
  */
4537
5544
  function createVirtualWorkspaceMembership(list) {
5545
+ if (!Object.isExtensible(list)) throw new Error("Workspace membership projection requires an extensible WorkspaceSource");
5546
+ const nativeGetSnapshot = list.getSnapshot.bind(list);
5547
+ const nativeSubscribe = list.subscribe.bind(list);
5548
+ const originalGetSnapshot = Object.getOwnPropertyDescriptor(list, "getSnapshot");
5549
+ const originalSubscribe = Object.getOwnPropertyDescriptor(list, "subscribe");
5550
+ const listeners = /* @__PURE__ */ new Set();
4538
5551
  let bindings = [];
5552
+ let nativeSnapshot = nativeGetSnapshot();
5553
+ let projectedSnapshot = projectVirtualWorkspaceMembership(nativeSnapshot, [], bindings);
4539
5554
  let disposed = false;
4540
- let applying = false;
4541
- const nativeSet = list.set;
4542
- const write = (next) => {
4543
- applying = true;
4544
- try {
4545
- nativeSet(next);
4546
- } finally {
4547
- applying = false;
4548
- }
5555
+ const project = (nextNativeSnapshot, previousBindings, nextBindings) => projectVirtualWorkspaceMembership(nextNativeSnapshot, previousBindings, nextBindings);
5556
+ const refreshSnapshot = () => {
5557
+ const nextNativeSnapshot = nativeGetSnapshot();
5558
+ if (nextNativeSnapshot === nativeSnapshot) return false;
5559
+ nativeSnapshot = nextNativeSnapshot;
5560
+ const nextProjectedSnapshot = project(nextNativeSnapshot, bindings, bindings);
5561
+ const changed = nextProjectedSnapshot !== projectedSnapshot;
5562
+ projectedSnapshot = nextProjectedSnapshot;
5563
+ return changed;
4549
5564
  };
4550
- list.set = (next) => {
4551
- write(projectVirtualWorkspaceMembership(next, bindings, bindings));
5565
+ const notify = () => {
5566
+ if (disposed) return;
5567
+ if (!refreshSnapshot()) return;
5568
+ for (const listener of [...listeners]) listener();
4552
5569
  };
4553
- const apply = (nextBindings) => {
4554
- const current = list.getSnapshot();
4555
- const next = projectVirtualWorkspaceMembership(current, bindings, nextBindings);
4556
- if (sameWorkspaceItems(current, next)) return;
4557
- write(next);
5570
+ const getSnapshot = () => {
5571
+ if (disposed) return nativeGetSnapshot();
5572
+ refreshSnapshot();
5573
+ return projectedSnapshot;
4558
5574
  };
4559
- const replay = () => {
4560
- if (disposed || applying) return;
4561
- apply(bindings);
5575
+ const subscribe = (listener) => {
5576
+ if (disposed) return () => void 0;
5577
+ listeners.add(listener);
5578
+ return () => listeners.delete(listener);
4562
5579
  };
4563
- const unsubscribe = list.subscribe(replay);
5580
+ Object.defineProperty(list, "getSnapshot", {
5581
+ configurable: true,
5582
+ enumerable: false,
5583
+ writable: true,
5584
+ value: getSnapshot
5585
+ });
5586
+ Object.defineProperty(list, "subscribe", {
5587
+ configurable: true,
5588
+ enumerable: false,
5589
+ writable: true,
5590
+ value: subscribe
5591
+ });
5592
+ const unsubscribeNative = nativeSubscribe(notify);
4564
5593
  const sync = (nextBindings) => {
4565
5594
  if (disposed) return;
4566
5595
  const normalized = normalizeBindings(nextBindings);
4567
- apply(normalized);
5596
+ if (sameBindings(bindings, normalized)) return;
5597
+ const previousBindings = bindings;
4568
5598
  bindings = normalized;
5599
+ nativeSnapshot = nativeGetSnapshot();
5600
+ const previousProjectedSnapshot = projectedSnapshot;
5601
+ projectedSnapshot = project(nativeSnapshot, previousBindings, bindings);
5602
+ if (projectedSnapshot === previousProjectedSnapshot) return;
5603
+ for (const listener of [...listeners]) listener();
5604
+ };
5605
+ const restoreMethod = (name, descriptor) => {
5606
+ if (descriptor === void 0) {
5607
+ delete list[name];
5608
+ return;
5609
+ }
5610
+ Object.defineProperty(list, name, descriptor);
4569
5611
  };
4570
5612
  return {
4571
5613
  ensure(binding) {
@@ -4579,11 +5621,14 @@ window.__ModuleLoader__.load({
4579
5621
  },
4580
5622
  dispose() {
4581
5623
  if (disposed) return;
4582
- apply([]);
4583
5624
  bindings = [];
5625
+ projectedSnapshot = nativeGetSnapshot();
4584
5626
  disposed = true;
4585
- unsubscribe();
4586
- list.set = nativeSet;
5627
+ for (const listener of [...listeners]) listener();
5628
+ unsubscribeNative();
5629
+ listeners.clear();
5630
+ restoreMethod("getSnapshot", originalGetSnapshot);
5631
+ restoreMethod("subscribe", originalSubscribe);
4587
5632
  }
4588
5633
  };
4589
5634
  }
@@ -4737,6 +5782,31 @@ window.__ModuleLoader__.load({
4737
5782
  }
4738
5783
  //#endregion
4739
5784
  //#region lib/client/worktree-session-fork.js
5785
+ function reconciliationSnapshot(snapshot) {
5786
+ if (typeof snapshot !== "object" || snapshot === null || snapshot.phase === "pending" || snapshot.phase !== void 0 && snapshot.phase !== "ready" || !Array.isArray(snapshot.ids) || typeof snapshot.byId !== "object" || snapshot.byId === null || Array.isArray(snapshot.byId)) return;
5787
+ for (const sessionId of snapshot.ids) {
5788
+ if (typeof sessionId !== "string") return void 0;
5789
+ const summary = snapshot.byId[sessionId];
5790
+ if (summary !== void 0 && (typeof summary !== "object" || summary === null || Array.isArray(summary))) return;
5791
+ const parentId = summary?.parentId;
5792
+ const origin = summary?.origin;
5793
+ const blank = summary?.blank;
5794
+ if (parentId !== void 0 && typeof parentId !== "string" || origin !== void 0 && typeof origin !== "string" || blank !== void 0 && typeof blank !== "boolean") return;
5795
+ }
5796
+ const candidates = snapshot.ids.flatMap((childSessionId) => {
5797
+ const summary = snapshot.byId[childSessionId];
5798
+ if (summary?.parentId === void 0 || summary.parentId === childSessionId || summary.blank === true || summary.origin === "subagent" || snapshot.byId[summary.parentId] === void 0) return [];
5799
+ return [{
5800
+ childSessionId,
5801
+ sourceSessionId: summary.parentId
5802
+ }];
5803
+ });
5804
+ const candidateFacts = candidates.map(({ childSessionId, sourceSessionId }) => [childSessionId, sourceSessionId]).sort(([leftChild, leftSource], [rightChild, rightSource]) => leftChild < rightChild || leftChild === rightChild && leftSource < rightSource ? -1 : leftChild === rightChild && leftSource === rightSource ? 0 : 1);
5805
+ return {
5806
+ signature: JSON.stringify([snapshot.phase ?? "ready", candidateFacts]),
5807
+ candidates
5808
+ };
5809
+ }
4740
5810
  function recoveryKey(sourceSessionId, childSessionId) {
4741
5811
  return `${sourceSessionId}\u0000${childSessionId}`;
4742
5812
  }
@@ -4751,18 +5821,22 @@ window.__ModuleLoader__.load({
4751
5821
  let pending = /* @__PURE__ */ new Map();
4752
5822
  let recoverySnapshot = {
4753
5823
  revision: 0,
4754
- pending: []
5824
+ pending: [],
5825
+ affectedWorkspaceIds: []
4755
5826
  };
4756
5827
  const subscribers = /* @__PURE__ */ new Set();
4757
5828
  const boundChildren = /* @__PURE__ */ new Set();
4758
5829
  const bindingInFlight = /* @__PURE__ */ new Map();
4759
5830
  let reconciliationInFlight;
4760
5831
  let reconciliationAgain = false;
4761
- const publish = () => {
5832
+ let reconciliationForce = false;
5833
+ let lastSessionLineageSignature;
5834
+ const publish = (affectedWorkspaceIds = []) => {
4762
5835
  revision += 1;
4763
5836
  recoverySnapshot = {
4764
5837
  revision,
4765
- pending: [...pending.values()]
5838
+ pending: [...pending.values()],
5839
+ affectedWorkspaceIds: [...new Set(affectedWorkspaceIds)]
4766
5840
  };
4767
5841
  for (const subscriber of subscribers) subscriber();
4768
5842
  };
@@ -4776,30 +5850,44 @@ window.__ModuleLoader__.load({
4776
5850
  ...target === void 0 ? {} : { binding: target },
4777
5851
  error
4778
5852
  });
4779
- publish();
5853
+ publish(target === void 0 ? [] : [target.workspaceId]);
4780
5854
  };
4781
5855
  const clearRecovery = (sourceSessionId, childSessionId) => {
4782
5856
  const key = recoveryKey(sourceSessionId, childSessionId);
4783
- if (!pending.has(key)) return;
5857
+ const current = pending.get(key);
5858
+ if (current === void 0) return { cleared: false };
4784
5859
  const next = new Map(pending);
4785
5860
  next.delete(key);
4786
5861
  pending = next;
4787
- publish();
5862
+ return {
5863
+ cleared: true,
5864
+ workspaceId: current.binding?.workspaceId
5865
+ };
4788
5866
  };
4789
- const attemptBinding = async (sourceSessionId, childSessionId) => {
4790
- if (disposed || boundChildren.has(childSessionId)) return { bound: false };
4791
- let target;
5867
+ const lookupBinding = async (sourceSessionId) => {
4792
5868
  try {
4793
- target = await options.findBinding(sourceSessionId);
5869
+ return (await options.findBindings([sourceSessionId])).bySessionId.get(sourceSessionId) ?? { status: "missing" };
4794
5870
  } catch (error) {
4795
- setRecovery(sourceSessionId, childSessionId, error);
5871
+ return {
5872
+ status: "error",
5873
+ error
5874
+ };
5875
+ }
5876
+ };
5877
+ const attemptBinding = async (sourceSessionId, childSessionId, providedLookup) => {
5878
+ if (disposed || boundChildren.has(childSessionId)) return { bound: false };
5879
+ const lookup = providedLookup ?? await lookupBinding(sourceSessionId);
5880
+ if (lookup.status === "error") {
5881
+ setRecovery(sourceSessionId, childSessionId, lookup.error);
4796
5882
  return { bound: false };
4797
5883
  }
4798
5884
  if (disposed) return { bound: false };
4799
- if (target === void 0 || target.status !== "active") {
4800
- clearRecovery(sourceSessionId, childSessionId);
5885
+ if (lookup.status === "missing" || lookup.binding.status !== "active") {
5886
+ const cleared = clearRecovery(sourceSessionId, childSessionId);
5887
+ if (cleared.cleared) publish(cleared.workspaceId === void 0 ? [] : [cleared.workspaceId]);
4801
5888
  return { bound: false };
4802
5889
  }
5890
+ const target = lookup.binding;
4803
5891
  try {
4804
5892
  await options.bindSession({
4805
5893
  workspaceId: target.workspaceId,
@@ -4814,50 +5902,64 @@ window.__ModuleLoader__.load({
4814
5902
  status: "active"
4815
5903
  };
4816
5904
  boundChildren.add(childSessionId);
4817
- clearRecovery(sourceSessionId, childSessionId);
5905
+ const { workspaceId: previousWorkspaceId } = clearRecovery(sourceSessionId, childSessionId);
4818
5906
  options.onBound?.(childBinding);
4819
- publish();
5907
+ publish([target.workspaceId, ...previousWorkspaceId === void 0 ? [] : [previousWorkspaceId]]);
4820
5908
  return { bound: true };
4821
5909
  } catch (error) {
4822
5910
  setRecovery(sourceSessionId, childSessionId, error, target);
4823
5911
  return { bound: false };
4824
5912
  }
4825
5913
  };
4826
- const bindChild = (sourceSessionId, childSessionId) => {
5914
+ const bindChild = (sourceSessionId, childSessionId, providedLookup) => {
4827
5915
  if (disposed || boundChildren.has(childSessionId)) return Promise.resolve({ bound: false });
4828
5916
  const key = recoveryKey(sourceSessionId, childSessionId);
4829
5917
  const current = bindingInFlight.get(key);
4830
5918
  if (current !== void 0) return current;
4831
- const promise = attemptBinding(sourceSessionId, childSessionId).finally(() => {
5919
+ const promise = attemptBinding(sourceSessionId, childSessionId, providedLookup).finally(() => {
4832
5920
  if (bindingInFlight.get(key) === promise) bindingInFlight.delete(key);
4833
5921
  });
4834
5922
  bindingInFlight.set(key, promise);
4835
5923
  return promise;
4836
5924
  };
4837
- const reconcileNow = async () => {
5925
+ const reconcileNow = async (force) => {
4838
5926
  if (disposed || options.sessions === void 0) return;
4839
- const snapshot = options.sessions.getSnapshot();
4840
- if (snapshot.phase === "pending") return;
4841
- if (!Array.isArray(snapshot.ids) || typeof snapshot.byId !== "object" || snapshot.byId === null) return;
4842
- const candidates = snapshot.ids.flatMap((childSessionId) => {
4843
- const summary = snapshot.byId[childSessionId];
4844
- if (summary?.parentId === void 0 || summary.parentId === childSessionId || summary.blank === true || summary.origin === "subagent" || snapshot.byId[summary.parentId] === void 0) return [];
4845
- return [{
4846
- childSessionId,
4847
- sourceSessionId: summary.parentId
4848
- }];
4849
- });
4850
- await Promise.all(candidates.map(({ childSessionId, sourceSessionId }) => bindChild(sourceSessionId, childSessionId).then(() => void 0)));
5927
+ const normalized = reconciliationSnapshot(options.sessions.getSnapshot());
5928
+ if (normalized === void 0) return;
5929
+ if (!force && normalized.signature === lastSessionLineageSignature) return;
5930
+ lastSessionLineageSignature = normalized.signature;
5931
+ const candidates = normalized.candidates.filter(({ childSessionId }) => !boundChildren.has(childSessionId));
5932
+ if (candidates.length === 0) return;
5933
+ const sourceSessionIds = [...new Set(candidates.map(({ sourceSessionId }) => sourceSessionId))];
5934
+ let index;
5935
+ try {
5936
+ index = await options.findBindings(sourceSessionIds);
5937
+ } catch (error) {
5938
+ const bySessionId = /* @__PURE__ */ new Map();
5939
+ for (const sourceSessionId of sourceSessionIds) bySessionId.set(sourceSessionId, {
5940
+ status: "error",
5941
+ error
5942
+ });
5943
+ index = { bySessionId };
5944
+ }
5945
+ if (disposed) return;
5946
+ await Promise.all(candidates.map(({ childSessionId, sourceSessionId }) => bindChild(sourceSessionId, childSessionId, index.bySessionId.get(sourceSessionId) ?? { status: "missing" }).then(() => void 0)));
4851
5947
  };
4852
- const reconcile = () => {
5948
+ const reconcile = (input = {}) => {
5949
+ const force = input.force === true;
4853
5950
  if (reconciliationInFlight !== void 0) {
4854
5951
  reconciliationAgain = true;
5952
+ reconciliationForce ||= force;
4855
5953
  return reconciliationInFlight;
4856
5954
  }
5955
+ let nextForce = force;
4857
5956
  const run = async () => {
4858
5957
  do {
5958
+ const forceThisPass = nextForce || reconciliationForce;
5959
+ nextForce = false;
5960
+ reconciliationForce = false;
4859
5961
  reconciliationAgain = false;
4860
- await reconcileNow();
5962
+ await reconcileNow(forceThisPass);
4861
5963
  } while (!disposed && reconciliationAgain);
4862
5964
  };
4863
5965
  const promise = run().finally(() => {
@@ -4885,7 +5987,11 @@ window.__ModuleLoader__.load({
4885
5987
  async retry(key) {
4886
5988
  const item = pending.get(key);
4887
5989
  if (item === void 0 || disposed) return false;
4888
- return (await bindChild(item.sourceSessionId, item.childSessionId)).bound;
5990
+ const providedLookup = item.binding === void 0 ? void 0 : {
5991
+ status: "found",
5992
+ binding: item.binding
5993
+ };
5994
+ return (await bindChild(item.sourceSessionId, item.childSessionId, providedLookup)).bound;
4889
5995
  },
4890
5996
  dispose() {
4891
5997
  disposed = true;
@@ -4896,27 +6002,56 @@ window.__ModuleLoader__.load({
4896
6002
  }
4897
6003
  //#endregion
4898
6004
  //#region lib/client/entry.js
6005
+ function forkRelatedSessionIds(snapshot) {
6006
+ if (typeof snapshot !== "object" || snapshot === null || !Array.isArray(snapshot.ids) || typeof snapshot.byId !== "object" || snapshot.byId === null || Array.isArray(snapshot.byId)) return;
6007
+ const related = /* @__PURE__ */ new Set();
6008
+ for (const childSessionId of snapshot.ids) {
6009
+ if (typeof childSessionId !== "string") return void 0;
6010
+ const summary = snapshot.byId[childSessionId];
6011
+ if (summary !== void 0 && (typeof summary !== "object" || summary === null || Array.isArray(summary))) return;
6012
+ const parentSessionId = summary?.parentId;
6013
+ if (parentSessionId === void 0 || parentSessionId === childSessionId || summary?.blank === true || summary?.origin === "subagent" || snapshot.byId[parentSessionId] === void 0) continue;
6014
+ related.add(childSessionId);
6015
+ related.add(parentSessionId);
6016
+ }
6017
+ return related;
6018
+ }
6019
+ function workspaceMembershipSignature(snapshot, sessions) {
6020
+ const relatedSessionIds = forkRelatedSessionIds(sessions);
6021
+ if (relatedSessionIds === void 0) return void 0;
6022
+ if (typeof snapshot !== "object" || snapshot === null || !Array.isArray(snapshot.items)) return;
6023
+ const facts = [];
6024
+ for (const workspace of snapshot.items) {
6025
+ if (typeof workspace !== "object" || workspace === null || typeof workspace.workspaceId !== "string" || !Array.isArray(workspace.sessionIds) || workspace.sessionIds.some((sessionId) => typeof sessionId !== "string")) return;
6026
+ facts.push([workspace.workspaceId, workspace.sessionIds.filter((sessionId) => relatedSessionIds.has(sessionId)).sort()]);
6027
+ }
6028
+ facts.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0);
6029
+ return JSON.stringify(facts);
6030
+ }
4899
6031
  /** Required DSH Client services; Connection is the sole Worktree wire dependency. */
4900
6032
  const inject = [
4901
6033
  "connection",
4902
6034
  "locale",
4903
6035
  "slots",
4904
6036
  "sessions",
4905
- "workspaces"
6037
+ "workspaces",
6038
+ "uiWorkspace"
4906
6039
  ];
4907
6040
  /**
4908
6041
  * DSH Client entry. The adapter is composed once per plugin fiber and is disposed
4909
6042
  * with that fiber, so slot consumers share one manager and one request lifetime.
4910
6043
  */
4911
6044
  function apply(ctx) {
6045
+ const locale = ctx.locale;
4912
6046
  if (typeof document !== "undefined") ctx.effect(() => installWorktreePermissionIcon(document), "clutch-dsh-worktree: permission icon cleanup");
4913
- ctx.effect(() => ctx.locale.register(WORKTREE_NS, {
6047
+ ctx.effect(() => locale.register(WORKTREE_NS, {
4914
6048
  zh,
4915
6049
  en
4916
6050
  }), "clutch-dsh-worktree: locale dictionaries");
4917
6051
  const manager = createWorktreeConnectionAdapter(ctx.connection.rpc);
6052
+ const viewReader = createWorktreeViewReader(manager);
4918
6053
  const fullAccessConfirmation = createWorktreeFullAccessConfirmationController();
4919
- const permissionNotice = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(void 0);
6054
+ const permissionNotice = createSnapshotStore(void 0);
4920
6055
  const permissionManager = typeof document !== "undefined" ? manager : void 0;
4921
6056
  const reportPermissionNotice = (input, result) => {
4922
6057
  const visible = result.status === "fallback-workspace-write" || result.status === "user-restricted" || result.status === "unverified";
@@ -4926,21 +6061,23 @@ window.__ModuleLoader__.load({
4926
6061
  } : void 0);
4927
6062
  };
4928
6063
  const sessions = ctx.sessions;
6064
+ const slots = ctx.slots;
4929
6065
  const virtualWorkspaceMembership = createVirtualWorkspaceMembership(ctx.workspaces.list);
4930
6066
  const contextProjection = createWorktreeContextProjection({
4931
6067
  sessions: ctx.sessions.list,
4932
6068
  workspaces: ctx.workspaces.list,
4933
- manager,
4934
- storeFactory: _deepseek_ai_dsh_client_runtime_client.createSnapshotStore
6069
+ viewReader,
6070
+ storeFactory: createSnapshotStore
4935
6071
  });
4936
6072
  ctx.effect(() => () => manager.dispose(), "clutch-dsh-worktree: connection cleanup");
6073
+ ctx.effect(() => () => viewReader.dispose(), "clutch-dsh-worktree: view reader cleanup");
4937
6074
  ctx.effect(() => () => fullAccessConfirmation.dispose(), "clutch-dsh-worktree: Full Access confirmation cleanup");
4938
6075
  ctx.effect(() => () => virtualWorkspaceMembership.dispose(), "clutch-dsh-worktree: Workspace membership cleanup");
4939
6076
  ctx.effect(() => () => contextProjection.dispose(), "clutch-dsh-worktree: Session context cleanup");
4940
6077
  contextProjection.refresh();
4941
6078
  const viewStore = createWorktreeViewStore();
4942
- const expandState = createWorktreeExpandStateStore(_deepseek_ai_dsh_client_runtime_client.createSnapshotStore);
4943
- const sessionOrder = createWorktreeSessionOrderStore(_deepseek_ai_dsh_client_runtime_client.createSnapshotStore);
6079
+ const expandState = createWorktreeExpandStateStore(createSnapshotStore);
6080
+ const sessionOrder = createWorktreeSessionOrderStore(createSnapshotStore);
4944
6081
  ctx.effect(() => () => sessionOrder.dispose(), "clutch-dsh-worktree: Session order cleanup");
4945
6082
  const ensureSessionWorkspace = (workspaceId, sessionId) => {
4946
6083
  virtualWorkspaceMembership.ensure({
@@ -4953,19 +6090,64 @@ window.__ModuleLoader__.load({
4953
6090
  };
4954
6091
  const forkableSessions = ctx.sessions;
4955
6092
  const nativeFork = forkableSessions.fork;
4956
- const findWorktreeSessionBinding = async (sessionId) => {
4957
- const workspaceIds = ctx.workspaces.list.getSnapshot().items.map((workspace) => workspace.workspaceId);
4958
- const results = await Promise.allSettled(workspaceIds.map(async (workspaceId) => {
4959
- return (await manager.listBindings({ workspaceId })).find((binding) => binding.sessionId === sessionId && binding.status === "active");
4960
- }));
4961
- const found = results.find((result) => result.status === "fulfilled" && result.value !== void 0);
4962
- if (found !== void 0) return found.value;
4963
- const failed = results.find((result) => result.status === "rejected");
4964
- if (failed !== void 0) throw failed.reason;
6093
+ const workspaceBindingReads = /* @__PURE__ */ new Map();
6094
+ const readWorkspaceBindings = (workspaceId) => {
6095
+ const current = workspaceBindingReads.get(workspaceId);
6096
+ if (current !== void 0) return current;
6097
+ const promise = manager.listBindings({ workspaceId }).finally(() => {
6098
+ if (workspaceBindingReads.get(workspaceId) === promise) workspaceBindingReads.delete(workspaceId);
6099
+ });
6100
+ workspaceBindingReads.set(workspaceId, promise);
6101
+ return promise;
6102
+ };
6103
+ const findWorktreeSessionBindings = async (sessionIds) => {
6104
+ const requested = [...new Set(sessionIds)];
6105
+ const requestedSet = new Set(requested);
6106
+ const workspaces = ctx.workspaces.list.getSnapshot().items;
6107
+ const workspaceIds = [...new Set(workspaces.map((workspace) => workspace.workspaceId))];
6108
+ const owners = /* @__PURE__ */ new Map();
6109
+ for (const workspace of workspaces) for (const sessionId of workspace.sessionIds) {
6110
+ if (!requestedSet.has(sessionId)) continue;
6111
+ const workspaceOwners = owners.get(sessionId) ?? [];
6112
+ if (!workspaceOwners.includes(workspace.workspaceId)) {
6113
+ workspaceOwners.push(workspace.workspaceId);
6114
+ owners.set(sessionId, workspaceOwners);
6115
+ }
6116
+ }
6117
+ const selectedWorkspaceIds = requested.some((sessionId) => (owners.get(sessionId)?.length ?? 0) === 0) ? workspaceIds : workspaceIds.filter((workspaceId) => requested.some((sessionId) => owners.get(sessionId)?.includes(workspaceId) === true));
6118
+ const results = await Promise.allSettled(selectedWorkspaceIds.map((workspaceId) => readWorkspaceBindings(workspaceId)));
6119
+ const resultByWorkspaceId = new Map(selectedWorkspaceIds.map((workspaceId, index) => [workspaceId, results[index]]));
6120
+ const bySessionId = /* @__PURE__ */ new Map();
6121
+ for (const sessionId of requested) {
6122
+ const relevantWorkspaceIds = owners.get(sessionId) ?? selectedWorkspaceIds;
6123
+ let found;
6124
+ let failed;
6125
+ for (const workspaceId of relevantWorkspaceIds) {
6126
+ const result = resultByWorkspaceId.get(workspaceId);
6127
+ if (result === void 0) continue;
6128
+ if (result.status === "rejected") {
6129
+ failed ??= result.reason;
6130
+ continue;
6131
+ }
6132
+ const binding = result.value.find((candidate) => candidate.sessionId === sessionId && candidate.status === "active");
6133
+ if (binding !== void 0) {
6134
+ found = binding;
6135
+ break;
6136
+ }
6137
+ }
6138
+ bySessionId.set(sessionId, found === void 0 ? failed === void 0 ? { status: "missing" } : {
6139
+ status: "error",
6140
+ error: failed
6141
+ } : {
6142
+ status: "found",
6143
+ binding: found
6144
+ });
6145
+ }
6146
+ return { bySessionId };
4965
6147
  };
4966
6148
  const forkCoordinator = typeof nativeFork !== "function" ? void 0 : createWorktreeSessionForkCoordinator({
4967
6149
  fork: (input) => nativeFork.call(ctx.sessions, input),
4968
- findBinding: findWorktreeSessionBinding,
6150
+ findBindings: findWorktreeSessionBindings,
4969
6151
  bindSession: (input) => manager.bindSession(input),
4970
6152
  sessions: ctx.sessions.list
4971
6153
  });
@@ -4974,8 +6156,15 @@ window.__ModuleLoader__.load({
4974
6156
  const reconcileForkChildren = () => {
4975
6157
  forkCoordinator.reconcile();
4976
6158
  };
6159
+ let lastWorkspaceMembershipSignature = workspaceMembershipSignature(ctx.workspaces.list.getSnapshot(), ctx.sessions.list.getSnapshot());
6160
+ const reconcileForkChildrenForWorkspace = () => {
6161
+ const nextSignature = workspaceMembershipSignature(ctx.workspaces.list.getSnapshot(), ctx.sessions.list.getSnapshot());
6162
+ const changed = nextSignature !== void 0 && nextSignature !== lastWorkspaceMembershipSignature;
6163
+ if (nextSignature !== void 0) lastWorkspaceMembershipSignature = nextSignature;
6164
+ forkCoordinator.reconcile({ force: changed });
6165
+ };
4977
6166
  const unsubscribeSessionList = ctx.sessions.list.subscribe(reconcileForkChildren);
4978
- const unsubscribeWorkspaceList = ctx.workspaces.list.subscribe(reconcileForkChildren);
6167
+ const unsubscribeWorkspaceList = ctx.workspaces.list.subscribe(reconcileForkChildrenForWorkspace);
4979
6168
  ctx.effect(() => () => {
4980
6169
  unsubscribeSessionList();
4981
6170
  unsubscribeWorkspaceList();
@@ -4987,7 +6176,7 @@ window.__ModuleLoader__.load({
4987
6176
  const worktreeSessionConnector = createWorktreeSessionConnector({
4988
6177
  manager,
4989
6178
  sessions: ctx.sessions.list,
4990
- archivedSessionIds: () => ctx.workspaces.list.getSnapshot().archivedSessionIds ?? [],
6179
+ archivedSessionIds: () => ctx.workspaces.list.getSnapshot().archivedSessionIds,
4991
6180
  createSession: async (input) => String(await sessions.create(input)),
4992
6181
  ensureSessionWorkspace,
4993
6182
  permission: permissionManager,
@@ -4998,21 +6187,21 @@ window.__ModuleLoader__.load({
4998
6187
  }
4999
6188
  });
5000
6189
  ctx.effect(() => () => worktreeSessionConnector.dispose(), "clutch-dsh-worktree: Worktree Session connector cleanup");
5001
- ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
6190
+ slots.inject("conversation.session.header.actions", () => slots.register({
5002
6191
  name: "conversation.session.header.actions",
5003
6192
  id: "clutch-dsh-worktree-context-header",
5004
6193
  order: -5,
5005
6194
  locale: WORKTREE_NS,
5006
6195
  inject: () => ({ hooks: { worktreeContext: contextProjection.store } })
5007
6196
  }, WorktreeHeaderContext));
5008
- ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
6197
+ slots.inject("sidebar.footer.action", () => slots.register({
5009
6198
  name: "sidebar.footer.action",
5010
6199
  id: "clutch-dsh-worktree-mode-action",
5011
6200
  store: viewStore,
5012
6201
  locale: WORKTREE_NS,
5013
6202
  inject: () => ({ available: true })
5014
6203
  }, WorktreeModeAction));
5015
- ctx.slots.inject("shell.overlay", () => ctx.slots.register({
6204
+ slots.inject("shell.overlay", () => slots.register({
5016
6205
  name: "shell.overlay",
5017
6206
  id: "clutch-dsh-worktree-navigation",
5018
6207
  store: viewStore,
@@ -5023,6 +6212,7 @@ window.__ModuleLoader__.load({
5023
6212
  sessionOrder,
5024
6213
  hooks: { worktreeContext: contextProjection.store },
5025
6214
  manager,
6215
+ viewReader,
5026
6216
  permission: permissionManager,
5027
6217
  confirmFullAccess: permissionManager === void 0 ? void 0 : fullAccessConfirmation.request,
5028
6218
  fullAccessConfirmation: typeof document === "undefined" ? void 0 : fullAccessConfirmation,
@@ -5030,13 +6220,13 @@ window.__ModuleLoader__.load({
5030
6220
  onPermissionNotice: reportPermissionNotice,
5031
6221
  permissionNotice,
5032
6222
  createWorkspace: async () => {
5033
- const workspacePath = await ctx.workspaces.pickDirectory();
6223
+ const workspacePath = await ctx.uiWorkspace.pickDirectory();
5034
6224
  if (workspacePath !== null) await ctx.workspaces.create({ path: workspacePath });
5035
6225
  },
5036
6226
  createSessionForWorktree: (input) => worktreeSessionConnector.create(input),
5037
6227
  invalidateWorktreeContext: (workspaceId) => contextProjection.invalidate(workspaceId),
5038
6228
  createMainSession: (workspaceId) => {
5039
- ctx.workspaces.startSession(workspaceId);
6229
+ ctx.uiWorkspace.startSession(workspaceId);
5040
6230
  },
5041
6231
  renameWorkspace: async (workspaceId, title) => {
5042
6232
  await ctx.workspaces.rename(workspaceId, title);