@cerbur/clutch-dsh-worktree 0.1.7 → 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 (159) hide show
  1. package/README.md +47 -32
  2. package/README.zh.md +39 -25
  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 +245 -53
  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/locales.d.ts +12 -0
  29. package/lib/client/locales.d.ts.map +1 -1
  30. package/lib/client/locales.js +12 -0
  31. package/lib/client/locales.js.map +1 -1
  32. package/lib/client/view-mode-store.d.ts +1 -1
  33. package/lib/client/view-mode-store.d.ts.map +1 -1
  34. package/lib/client/view-mode-store.js +1 -1
  35. package/lib/client/view-mode-store.js.map +1 -1
  36. package/lib/client/view-mode.d.ts +20 -6
  37. package/lib/client/view-mode.d.ts.map +1 -1
  38. package/lib/client/view-mode.js +35 -10
  39. package/lib/client/view-mode.js.map +1 -1
  40. package/lib/client/virtual-workspace-membership.d.ts +12 -10
  41. package/lib/client/virtual-workspace-membership.d.ts.map +1 -1
  42. package/lib/client/virtual-workspace-membership.js +82 -57
  43. package/lib/client/virtual-workspace-membership.js.map +1 -1
  44. package/lib/client/worktree-context-store.d.ts +7 -15
  45. package/lib/client/worktree-context-store.d.ts.map +1 -1
  46. package/lib/client/worktree-context-store.js +20 -13
  47. package/lib/client/worktree-context-store.js.map +1 -1
  48. package/lib/client/worktree-context.js +1 -1
  49. package/lib/client/worktree-context.js.map +1 -1
  50. package/lib/client/worktree-error-copy.d.ts.map +1 -1
  51. package/lib/client/worktree-error-copy.js +8 -0
  52. package/lib/client/worktree-error-copy.js.map +1 -1
  53. package/lib/client/worktree-expand-state.d.ts +5 -4
  54. package/lib/client/worktree-expand-state.d.ts.map +1 -1
  55. package/lib/client/worktree-expand-state.js.map +1 -1
  56. package/lib/client/worktree-session-fork.d.ts +18 -3
  57. package/lib/client/worktree-session-fork.d.ts.map +1 -1
  58. package/lib/client/worktree-session-fork.js +125 -36
  59. package/lib/client/worktree-session-fork.js.map +1 -1
  60. package/lib/client/worktree-session-order.d.ts +2 -2
  61. package/lib/client/worktree-session-order.d.ts.map +1 -1
  62. package/lib/client/worktree-session.d.ts.map +1 -1
  63. package/lib/client/worktree-session.js +3 -1
  64. package/lib/client/worktree-session.js.map +1 -1
  65. package/lib/client/worktree-surface-rows.d.ts.map +1 -1
  66. package/lib/client/worktree-surface-rows.js +8 -1
  67. package/lib/client/worktree-surface-rows.js.map +1 -1
  68. package/lib/client/worktree-surface-types.d.ts +19 -1
  69. package/lib/client/worktree-surface-types.d.ts.map +1 -1
  70. package/lib/client/worktree-view-read.d.ts +18 -8
  71. package/lib/client/worktree-view-read.d.ts.map +1 -1
  72. package/lib/client/worktree-view-read.js +75 -10
  73. package/lib/client/worktree-view-read.js.map +1 -1
  74. package/lib/client.js +1404 -178
  75. package/lib/client.js.map +1 -1
  76. package/lib/contract/index.d.ts +6 -2
  77. package/lib/contract/index.d.ts.map +1 -1
  78. package/lib/contract/index.js +4 -0
  79. package/lib/contract/index.js.map +1 -1
  80. package/lib/host/dsh-read-adapter.d.ts +1 -0
  81. package/lib/host/dsh-read-adapter.d.ts.map +1 -1
  82. package/lib/host/dsh-read-adapter.js +6 -0
  83. package/lib/host/dsh-read-adapter.js.map +1 -1
  84. package/lib/host/service.d.ts +2 -0
  85. package/lib/host/service.d.ts.map +1 -1
  86. package/lib/host/service.js +6 -1
  87. package/lib/host/service.js.map +1 -1
  88. package/lib/host/worktree-permission-manager.d.ts.map +1 -1
  89. package/lib/host/worktree-permission-manager.js +3 -1
  90. package/lib/host/worktree-permission-manager.js.map +1 -1
  91. package/lib/host/worktree-permission.d.ts +3 -2
  92. package/lib/host/worktree-permission.d.ts.map +1 -1
  93. package/lib/host/worktree-permission.js +29 -5
  94. package/lib/host/worktree-permission.js.map +1 -1
  95. package/lib/index.d.ts +2 -1
  96. package/lib/index.d.ts.map +1 -1
  97. package/lib/index.js +1 -0
  98. package/lib/index.js.map +1 -1
  99. package/lib/manage/manager-context.d.ts +2 -0
  100. package/lib/manage/manager-context.d.ts.map +1 -1
  101. package/lib/manage/manager-worktrees.d.ts +5 -0
  102. package/lib/manage/manager-worktrees.d.ts.map +1 -1
  103. package/lib/manage/manager-worktrees.js +130 -39
  104. package/lib/manage/manager-worktrees.js.map +1 -1
  105. package/lib/manage/manager.d.ts +20 -0
  106. package/lib/manage/manager.d.ts.map +1 -1
  107. package/lib/manage/manager.js +93 -13
  108. package/lib/manage/manager.js.map +1 -1
  109. package/lib/manage/types.d.ts +9 -1
  110. package/lib/manage/types.d.ts.map +1 -1
  111. package/lib/provider/git.d.ts +37 -9
  112. package/lib/provider/git.d.ts.map +1 -1
  113. package/lib/provider/git.js +166 -61
  114. package/lib/provider/git.js.map +1 -1
  115. package/lib/provider/index.d.ts +5 -1
  116. package/lib/provider/index.d.ts.map +1 -1
  117. package/lib/provider/index.js +4 -0
  118. package/lib/provider/index.js.map +1 -1
  119. package/lib/provider/mutation-lock.d.ts +37 -0
  120. package/lib/provider/mutation-lock.d.ts.map +1 -0
  121. package/lib/provider/mutation-lock.js +270 -0
  122. package/lib/provider/mutation-lock.js.map +1 -0
  123. package/lib/provider/mutation-token.d.ts +8 -0
  124. package/lib/provider/mutation-token.d.ts.map +1 -0
  125. package/lib/provider/mutation-token.js +20 -0
  126. package/lib/provider/mutation-token.js.map +1 -0
  127. package/lib/provider/repository-fingerprint.d.ts +8 -0
  128. package/lib/provider/repository-fingerprint.d.ts.map +1 -0
  129. package/lib/provider/repository-fingerprint.js +13 -0
  130. package/lib/provider/repository-fingerprint.js.map +1 -0
  131. package/lib/provider/sidecar-persistence.d.ts +7 -3
  132. package/lib/provider/sidecar-persistence.d.ts.map +1 -1
  133. package/lib/provider/sidecar-persistence.js +118 -44
  134. package/lib/provider/sidecar-persistence.js.map +1 -1
  135. package/lib/provider/sidecar-schema.d.ts +1 -1
  136. package/lib/provider/sidecar-schema.d.ts.map +1 -1
  137. package/lib/provider/sidecar-schema.js +140 -8
  138. package/lib/provider/sidecar-schema.js.map +1 -1
  139. package/lib/provider/sidecar.d.ts +3 -1
  140. package/lib/provider/sidecar.d.ts.map +1 -1
  141. package/lib/provider/sidecar.js +7 -2
  142. package/lib/provider/sidecar.js.map +1 -1
  143. package/lib/provider/subprocess.d.ts +37 -0
  144. package/lib/provider/subprocess.d.ts.map +1 -0
  145. package/lib/provider/subprocess.js +327 -0
  146. package/lib/provider/subprocess.js.map +1 -0
  147. package/lib/provider/transaction.d.ts +65 -0
  148. package/lib/provider/transaction.d.ts.map +1 -0
  149. package/lib/provider/transaction.js +1011 -0
  150. package/lib/provider/transaction.js.map +1 -0
  151. package/lib/provider/types.d.ts +98 -7
  152. package/lib/provider/types.d.ts.map +1 -1
  153. package/lib/provider/types.js +1 -1
  154. package/lib/provider/types.js.map +1 -1
  155. package/lib/typert.host.js +29 -25
  156. package/lib/typert.remote-client.d.ts +2 -2
  157. package/lib/typert.remote-client.d.ts.map +1 -1
  158. package/lib/typert.remote-client.js +29 -25
  159. package/package.json +48 -32
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 = {
@@ -36,6 +781,7 @@ window.__ModuleLoader__.load({
36
781
  "worktree.mainWithBranch": "本地({branch})",
37
782
  "worktree.detached": "已分离 Worktree",
38
783
  "worktree.repair": "Worktree 需要修复",
784
+ "worktree.recovery": "Worktree 需要恢复",
39
785
  "worktree.ready": "活动 Worktree 已就绪",
40
786
  "worktree.expand": "展开 {name}",
41
787
  "worktree.collapse": "收起 {name}",
@@ -72,6 +818,7 @@ window.__ModuleLoader__.load({
72
818
  "session.rename": "重命名会话",
73
819
  "session.fork": "Fork 会话",
74
820
  "session.archive": "归档会话",
821
+ "session.copyId": "复制 Session ID",
75
822
  "session.expandMore": "展开其余 {count} 个会话",
76
823
  "session.collapse": "收起",
77
824
  "session.name": "会话名称",
@@ -125,6 +872,10 @@ window.__ModuleLoader__.load({
125
872
  "error.worktreeRecordMissing": "Worktree 注册未返回 Worktree 记录,请重试请求。",
126
873
  "error.worktreeImportInvalid": "这个 Worktree 无法导入,请选择同一 Workspace 中有效的绝对路径。",
127
874
  "error.worktreeAlreadyManaged": "这个 Worktree 已由插件管理。",
875
+ "error.worktreeMutationBusy": "另一个 DSH 实例正在修改 Worktree 状态,请稍后重试。",
876
+ "error.worktreeStateConflict": "Worktree 状态已经变化,请刷新后重试。",
877
+ "error.worktreeRecoveryRequired": "Worktree 状态需要恢复;请先完成恢复后再重试破坏性操作。",
878
+ "error.worktreeIdentityChanged": "Worktree 或 repository 身份已经变化,需要恢复后再操作。",
128
879
  "error.worktreeRegistrationSessionUnavailable": "Worktree 已注册,但 Session 创建不可用,请重新连接后重试。",
129
880
  "error.workspaceRenameUnavailable": "工作区重命名不可用,请重新连接后重试。",
130
881
  "error.workspaceDeleteUnavailable": "工作区删除不可用,请重新连接后重试。",
@@ -167,6 +918,7 @@ window.__ModuleLoader__.load({
167
918
  "worktree.mainWithBranch": "Local ({branch})",
168
919
  "worktree.detached": "Detached Worktree",
169
920
  "worktree.repair": "Worktree needs repair",
921
+ "worktree.recovery": "Worktree requires recovery",
170
922
  "worktree.ready": "Active Worktree ready",
171
923
  "worktree.expand": "Expand {name}",
172
924
  "worktree.collapse": "Collapse {name}",
@@ -203,6 +955,7 @@ window.__ModuleLoader__.load({
203
955
  "session.rename": "Rename session",
204
956
  "session.fork": "Fork session",
205
957
  "session.archive": "Archive session",
958
+ "session.copyId": "Copy session ID",
206
959
  "session.expandMore": "Expand {count} more",
207
960
  "session.collapse": "Collapse",
208
961
  "session.name": "Session name",
@@ -256,6 +1009,10 @@ window.__ModuleLoader__.load({
256
1009
  "error.worktreeRecordMissing": "Worktree registration returned no Worktree record; retry the request.",
257
1010
  "error.worktreeImportInvalid": "This Worktree cannot be imported. Choose a valid absolute path in this Workspace.",
258
1011
  "error.worktreeAlreadyManaged": "This Worktree is already managed by the plugin.",
1012
+ "error.worktreeMutationBusy": "Another DSH instance is mutating Worktree state; retry shortly.",
1013
+ "error.worktreeStateConflict": "The Worktree state changed; refresh and retry the request.",
1014
+ "error.worktreeRecoveryRequired": "Worktree state requires recovery; resolve it before retrying destructive actions.",
1015
+ "error.worktreeIdentityChanged": "The Worktree or repository identity changed; recovery is required before acting.",
259
1016
  "error.worktreeRegistrationSessionUnavailable": "The Worktree was registered, but Session creation is unavailable; retry after reconnecting.",
260
1017
  "error.workspaceRenameUnavailable": "Workspace rename is unavailable; retry after reconnecting.",
261
1018
  "error.workspaceDeleteUnavailable": "Workspace delete is unavailable; retry after reconnecting.",
@@ -414,7 +1171,7 @@ window.__ModuleLoader__.load({
414
1171
  };
415
1172
  }
416
1173
  //#endregion
417
- //#region \0clutch-dsh-worktree-css:/private/tmp/clutch-dsh-wt-worktree-0.1.7-release/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
418
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";
419
1176
  const styleId$1 = "@cerbur/clutch-dsh-worktree/worktree-context.css";
420
1177
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree-context.css\"]") === null) {
@@ -455,7 +1212,9 @@ window.__ModuleLoader__.load({
455
1212
  className: worktree_context_css_default.contextHoverTitle,
456
1213
  children: value.label
457
1214
  }),
458
- openDelayMs: 500
1215
+ openDelayMs: 500,
1216
+ copyLabel: t("copy"),
1217
+ copiedLabel: t("hover.copied")
459
1218
  });
460
1219
  }
461
1220
  /** Render the current branch or active Worktree branch beside the Session title. */
@@ -468,7 +1227,7 @@ window.__ModuleLoader__.load({
468
1227
  });
469
1228
  }
470
1229
  //#endregion
471
- //#region \0clutch-dsh-worktree-css:/private/tmp/clutch-dsh-wt-worktree-0.1.7-release/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
472
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";
473
1232
  const styleId = "@cerbur/clutch-dsh-worktree/worktree.css";
474
1233
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"@cerbur/clutch-dsh-worktree/worktree.css\"]") === null) {
@@ -688,7 +1447,9 @@ window.__ModuleLoader__.load({
688
1447
  className: worktree_context_css_default.contextHoverTitle,
689
1448
  children: label
690
1449
  }),
691
- openDelayMs: 500
1450
+ openDelayMs: 500,
1451
+ copyLabel: t("copy"),
1452
+ copiedLabel: t("hover.copied")
692
1453
  })
693
1454
  });
694
1455
  }
@@ -924,11 +1685,6 @@ window.__ModuleLoader__.load({
924
1685
  const bound = new Set(boundSessionIds);
925
1686
  return sessionIds.filter((sessionId) => !bound.has(sessionId));
926
1687
  }
927
- /**
928
- * Apply a browser-only membership delta to a DSH Workspace list snapshot.
929
- * `previousBindings` are removed first so the same function can also undo a
930
- * projection after a binding is deleted or the plugin is disposed.
931
- */
932
1688
  function projectVirtualWorkspaceMembership(snapshot, previousBindings, nextBindings) {
933
1689
  const previousSessionIds = new Set(previousBindings.map((binding) => binding.sessionId));
934
1690
  const nextByWorkspace = /* @__PURE__ */ new Map();
@@ -953,6 +1709,34 @@ window.__ModuleLoader__.load({
953
1709
  items
954
1710
  };
955
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
+ }
956
1740
  //#endregion
957
1741
  //#region lib/client/worktree-error-copy.js
958
1742
  function detail(error, name) {
@@ -986,6 +1770,10 @@ window.__ModuleLoader__.load({
986
1770
  case "WORKTREE_RECORD_MISSING": return t("error.worktreeRecordMissing");
987
1771
  case "WORKTREE_IMPORT_INVALID": return t("error.worktreeImportInvalid");
988
1772
  case "WORKTREE_ALREADY_MANAGED": return t("error.worktreeAlreadyManaged");
1773
+ case "WORKTREE_MUTATION_BUSY": return t("error.worktreeMutationBusy");
1774
+ case "WORKTREE_STATE_CONFLICT": return t("error.worktreeStateConflict");
1775
+ case "WORKTREE_RECOVERY_REQUIRED": return t("error.worktreeRecoveryRequired");
1776
+ case "WORKTREE_IDENTITY_CHANGED": return t("error.worktreeIdentityChanged");
989
1777
  case "WORKTREE_REGISTRATION_SESSION_UNAVAILABLE": return t("error.worktreeRegistrationSessionUnavailable");
990
1778
  case "WORKSPACE_RENAME_UNAVAILABLE": return t("error.workspaceRenameUnavailable");
991
1779
  case "WORKSPACE_DELETE_UNAVAILABLE": return t("error.workspaceDeleteUnavailable");
@@ -1504,6 +2292,15 @@ window.__ModuleLoader__.load({
1504
2292
  merged[index] = nextView;
1505
2293
  return merged;
1506
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
+ }
1507
2304
  /** Reuse the previous ID snapshot when DSH republishes equivalent Workspace items. */
1508
2305
  function stableWorkspaceIds(previous, next) {
1509
2306
  if (previous.length !== next.length) return next;
@@ -1583,6 +2380,65 @@ window.__ModuleLoader__.load({
1583
2380
  error: viewError
1584
2381
  };
1585
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
+ }
1586
2442
  /** Read all three Worktree projections needed by the surface in one refresh. */
1587
2443
  async function loadWorktreeView(manager, workspaceId) {
1588
2444
  const [worktreesResult, branchesResult, bindingsResult] = await Promise.allSettled([
@@ -1609,28 +2465,16 @@ window.__ModuleLoader__.load({
1609
2465
  readiness: branchesResult.value.length > 0 ? { status: "ready" } : { status: "noLocalBranch" }
1610
2466
  };
1611
2467
  }
1612
- /** Isolate modal-target reads from full-surface refresh generations. */
1613
- function createWorktreeModalViewLoader() {
2468
+ /** Isolate modal-target callbacks while sharing the Client Workspace reader. */
2469
+ function createWorktreeModalViewLoader(reader) {
1614
2470
  const guard = createWorktreeRefreshGuard();
1615
2471
  return {
1616
2472
  invalidate: guard.invalidate,
1617
- load(manager, workspaceId, onSuccess, onError) {
1618
- return guard.run(() => loadWorktreeView(manager, workspaceId), (data) => onSuccess({
1619
- workspaceId,
1620
- ...data
1621
- }), (error) => onError(toWorktreeViewError(error)));
2473
+ load(workspaceId, onSuccess, onError) {
2474
+ return guard.run(() => reader.read(workspaceId), onSuccess, (error) => onError(toWorktreeViewError(error)));
1622
2475
  }
1623
2476
  };
1624
2477
  }
1625
- /** Load one independent projection per DSH Workspace for the flat sidebar hierarchy. */
1626
- async function loadWorktreeViews(manager, workspaceIds, options = {}) {
1627
- const views = await Promise.all(workspaceIds.map(async (workspaceId) => ({
1628
- workspaceId,
1629
- ...await loadWorktreeView(manager, workspaceId)
1630
- })));
1631
- if (options.invalidateContext !== false) await options.invalidateWorktreeContext?.();
1632
- return views;
1633
- }
1634
2478
  /** Hide DSH-archived Sessions from the browser-local Worktree projection. */
1635
2479
  function filterArchivedSessionIds(sessionIds, archivedSessionIds) {
1636
2480
  return sessionIds.filter((sessionId) => !archivedSessionIds.includes(sessionId));
@@ -1698,7 +2542,7 @@ window.__ModuleLoader__.load({
1698
2542
  }, result);
1699
2543
  }
1700
2544
  function resolveWorktreeSessionAction(input) {
1701
- if (input.target.status !== "active" || input.target.health === "repair") return {
2545
+ if (input.target.status !== "active" || input.target.health === "repair" || input.target.health === "recovery-needed") return {
1702
2546
  kind: "reject",
1703
2547
  reason: "worktree-not-available"
1704
2548
  };
@@ -2601,7 +3445,9 @@ window.__ModuleLoader__.load({
2601
3445
  children: label
2602
3446
  }),
2603
3447
  openDelayMs: 500,
2604
- disabled: menu?.open === true
3448
+ disabled: menu?.open === true,
3449
+ copyLabel: t("copy"),
3450
+ copiedLabel: t("hover.copied")
2605
3451
  });
2606
3452
  }
2607
3453
  /** Worktree-mode Session row with the same trailing options menu as native DSH rows. */
@@ -2626,6 +3472,11 @@ window.__ModuleLoader__.load({
2626
3472
  label: t("session.archive"),
2627
3473
  icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconArchiveOutline20, { size: 16 }),
2628
3474
  disabled: onArchive === void 0 || actionPending
3475
+ },
3476
+ {
3477
+ id: "copy-session-id",
3478
+ label: t("session.copyId"),
3479
+ icon: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, {})
2629
3480
  }
2630
3481
  ];
2631
3482
  const statusLabel = presentation === void 0 ? void 0 : sessionStatusLabel(t, presentation.status);
@@ -2697,6 +3548,7 @@ window.__ModuleLoader__.load({
2697
3548
  if (id === "rename") onRename?.(sessionId, label);
2698
3549
  if (id === "fork") onFork?.(sessionId);
2699
3550
  if (id === "archive") onArchive?.(sessionId);
3551
+ if (id === "copy-session-id") (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(sessionId);
2700
3552
  },
2701
3553
  portal: true,
2702
3554
  closeOnPointerLeave: true,
@@ -2796,7 +3648,8 @@ window.__ModuleLoader__.load({
2796
3648
  const EMPTY_FULL_ACCESS_CONFIRMATION_SNAPSHOT = () => void 0;
2797
3649
  const EMPTY_FORK_RECOVERY_SNAPSHOT = {
2798
3650
  revision: 0,
2799
- pending: []
3651
+ pending: [],
3652
+ affectedWorkspaceIds: []
2800
3653
  };
2801
3654
  const EMPTY_FORK_RECOVERY_STORE = {
2802
3655
  getSnapshot: () => EMPTY_FORK_RECOVERY_SNAPSHOT,
@@ -2827,7 +3680,7 @@ window.__ModuleLoader__.load({
2827
3680
  * Peer Worktree navigation surface. It keeps the original DSH Workspace mode
2828
3681
  * intact and renders a browser-local Workspace → Worktree → Session projection.
2829
3682
  */
2830
- 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 }) {
2831
3684
  const mode = effectiveViewMode(useStore((state) => state.viewMode), available && manager !== void 0);
2832
3685
  const sessions = useSessions((state) => state);
2833
3686
  const workspaces = useWorkspaces((state) => state);
@@ -2835,6 +3688,8 @@ window.__ModuleLoader__.load({
2835
3688
  const forkRecoverySnapshot = (0, react.useSyncExternalStore)(forkRecoveryStore.subscribe, forkRecoveryStore.getSnapshot, forkRecoveryStore.getSnapshot);
2836
3689
  const currentSessionId = sessions.current;
2837
3690
  const workspaceIds = useStableWorkspaceIds(workspaces.items);
3691
+ const workspaceIdsRef = (0, react.useRef)(workspaceIds);
3692
+ workspaceIdsRef.current = workspaceIds;
2838
3693
  const [readState, setReadState] = (0, react.useState)(EMPTY_READ_STATE);
2839
3694
  const expandSnapshot = (0, react.useSyncExternalStore)(expandState.subscribe, expandState.getSnapshot, expandState.getSnapshot);
2840
3695
  const permissionNoticeSnapshot = (0, react.useSyncExternalStore)(permissionNotice?.subscribe ?? EMPTY_PERMISSION_NOTICE_SUBSCRIBE, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT, permissionNotice?.getSnapshot ?? EMPTY_PERMISSION_NOTICE_SNAPSHOT);
@@ -2897,8 +3752,9 @@ window.__ModuleLoader__.load({
2897
3752
  const [worktreeDrag, setWorktreeDrag] = (0, react.useState)();
2898
3753
  const worktreeDropCommitted = (0, react.useRef)(false);
2899
3754
  const refreshGuard = (0, react.useRef)(createWorktreeRefreshGuard());
3755
+ const targetRefreshGuards = (0, react.useRef)(/* @__PURE__ */ new Map());
2900
3756
  const forkRecoveryRevisionRef = (0, react.useRef)(forkRecoverySnapshot.revision);
2901
- const modalReadLoader = (0, react.useRef)(createWorktreeModalViewLoader());
3757
+ const modalReadLoader = (0, react.useRef)(createWorktreeModalViewLoader(viewReader));
2902
3758
  const modalReadViewRef = (0, react.useRef)();
2903
3759
  const importCandidatesGuard = (0, react.useRef)(createWorktreeRefreshGuard());
2904
3760
  const modalWorkspaceIdRef = (0, react.useRef)(worktreeModalWorkspaceId);
@@ -2908,37 +3764,112 @@ window.__ModuleLoader__.load({
2908
3764
  const query = searchQuery.trim().toLocaleLowerCase();
2909
3765
  const archivedSessionIds = workspaces.archivedSessionIds ?? [];
2910
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
+ };
2911
3774
  const refresh = (0, react.useCallback)(async (options = {}) => {
2912
3775
  if (manager === void 0) {
2913
3776
  refreshGuard.current.invalidate();
3777
+ for (const guard of targetRefreshGuards.current.values()) guard.invalidate();
2914
3778
  setReadState(EMPTY_READ_STATE);
2915
3779
  return;
2916
3780
  }
3781
+ const scope = options.scope ?? { kind: "global" };
2917
3782
  const preserveCurrent = options.preserveCurrent === true;
2918
- if (!preserveCurrent) setReadState({
2919
- status: "loading",
2920
- views: []
2921
- });
2922
- await refreshGuard.current.run(() => loadWorktreeViews(manager, workspaceIds, {
2923
- invalidateContext: options.invalidateContext !== false,
2924
- invalidateWorktreeContext
2925
- }), (views) => {
2926
- setReadState({
2927
- status: "ready",
2928
- 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: []
2929
3788
  });
2930
- }, (error) => {
2931
- if (preserveCurrent) throw error;
2932
- setReadState({
2933
- status: "error",
2934
- views: modalReadViewRef.current === void 0 ? [] : [modalReadViewRef.current],
2935
- 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
+ });
2936
3810
  });
2937
- });
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
+ }));
2938
3869
  }, [
2939
3870
  invalidateWorktreeContext,
2940
3871
  manager,
2941
- workspaceIds
3872
+ viewReader
2942
3873
  ]);
2943
3874
  const loadModalWorktreeView = (0, react.useCallback)((workspaceId) => {
2944
3875
  setModalReadError(void 0);
@@ -2952,7 +3883,7 @@ window.__ModuleLoader__.load({
2952
3883
  });
2953
3884
  return;
2954
3885
  }
2955
- modalReadLoader.current.load(manager, workspaceId, (view) => {
3886
+ modalReadLoader.current.load(workspaceId, (view) => {
2956
3887
  modalReadViewRef.current = view;
2957
3888
  setModalReadLoading(false);
2958
3889
  setReadState((current) => ({
@@ -2963,11 +3894,12 @@ window.__ModuleLoader__.load({
2963
3894
  setModalReadLoading(false);
2964
3895
  setModalReadError(toWorktreeViewError(error));
2965
3896
  });
2966
- }, [manager]);
3897
+ }, [manager, viewReader]);
2967
3898
  (0, react.useEffect)(() => {
2968
3899
  if (mode === "worktree") refresh({ preserveCurrent: readStateRef.current.status === "ready" });
2969
3900
  else {
2970
3901
  refreshGuard.current.invalidate();
3902
+ for (const guard of targetRefreshGuards.current.values()) guard.invalidate();
2971
3903
  modalReadLoader.current.invalidate();
2972
3904
  modalReadViewRef.current = void 0;
2973
3905
  setWorktreeModalWorkspaceId(void 0);
@@ -2976,15 +3908,60 @@ window.__ModuleLoader__.load({
2976
3908
  setReadState(EMPTY_READ_STATE);
2977
3909
  }
2978
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
+ ]);
2979
3951
  (0, react.useEffect)(() => {
2980
3952
  if (forkRecoveryRevisionRef.current === forkRecoverySnapshot.revision) return;
2981
3953
  forkRecoveryRevisionRef.current = forkRecoverySnapshot.revision;
2982
3954
  if (mode !== "worktree" || manager === void 0) return;
3955
+ if (forkRecoverySnapshot.affectedWorkspaceIds.length === 0) return;
2983
3956
  refresh({
2984
- preserveCurrent: readStateRef.current.status === "ready",
2985
- invalidateContext: false
3957
+ scope: {
3958
+ kind: "workspaces",
3959
+ workspaceIds: forkRecoverySnapshot.affectedWorkspaceIds
3960
+ },
3961
+ preserveCurrent: readStateRef.current.status === "ready"
2986
3962
  }).catch(() => {});
2987
3963
  }, [
3964
+ forkRecoverySnapshot.affectedWorkspaceIds,
2988
3965
  forkRecoverySnapshot.revision,
2989
3966
  manager,
2990
3967
  mode,
@@ -3127,12 +4104,12 @@ window.__ModuleLoader__.load({
3127
4104
  return createDefaultWorktreeName([...modalView.branches.map((branch) => branch.name), ...modalView.worktrees.map((worktree) => worktree.branch)]);
3128
4105
  });
3129
4106
  }, [modalView, worktreeModalWorkspaceId]);
3130
- const runMutation = async (operation) => {
4107
+ const runMutation = async (operation, refreshOptions) => {
3131
4108
  setActionPending(true);
3132
4109
  setActionError(void 0);
3133
4110
  try {
3134
4111
  await operation();
3135
- await refresh({ preserveCurrent: true });
4112
+ if (refreshOptions !== void 0) await refresh(refreshOptions);
3136
4113
  } catch (error) {
3137
4114
  setActionError(toWorktreeViewError(error));
3138
4115
  } finally {
@@ -3299,6 +4276,10 @@ window.__ModuleLoader__.load({
3299
4276
  }
3300
4277
  setActionError(void 0);
3301
4278
  insertWorktreeBefore(workspaceId, activeDrag.worktreeId, move.beforeWorktreeId).then(() => refresh({
4279
+ scope: {
4280
+ kind: "workspace",
4281
+ workspaceId
4282
+ },
3302
4283
  preserveCurrent: true,
3303
4284
  invalidateContext: false
3304
4285
  })).catch((error) => {
@@ -3455,7 +4436,13 @@ window.__ModuleLoader__.load({
3455
4436
  const continueWorktreeRegistration = async (registeredWorktree) => {
3456
4437
  closeWorktreeCreator(true);
3457
4438
  if (createSessionCallback === void 0) {
3458
- await refresh({ preserveCurrent: true });
4439
+ await refresh({
4440
+ scope: {
4441
+ kind: "workspace",
4442
+ workspaceId: registeredWorktree.workspaceId
4443
+ },
4444
+ preserveCurrent: true
4445
+ });
3459
4446
  setActionError({
3460
4447
  code: "WORKTREE_REGISTRATION_SESSION_UNAVAILABLE",
3461
4448
  message: "",
@@ -3470,7 +4457,6 @@ window.__ModuleLoader__.load({
3470
4457
  };
3471
4458
  try {
3472
4459
  await createSessionCallback(sessionInput);
3473
- await invalidateWorktreeContext?.(registeredWorktree.workspaceId);
3474
4460
  } catch (error) {
3475
4461
  if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
3476
4462
  ...sessionInput,
@@ -3483,7 +4469,13 @@ window.__ModuleLoader__.load({
3483
4469
  });
3484
4470
  throw error;
3485
4471
  }
3486
- await refresh({ preserveCurrent: true });
4472
+ await refresh({
4473
+ scope: {
4474
+ kind: "workspace",
4475
+ workspaceId: registeredWorktree.workspaceId
4476
+ },
4477
+ preserveCurrent: true
4478
+ });
3487
4479
  };
3488
4480
  const submitWorktree = async () => {
3489
4481
  const worktreeName = newBranch.trim();
@@ -3535,8 +4527,13 @@ window.__ModuleLoader__.load({
3535
4527
  setPendingSessionBinding(void 0);
3536
4528
  try {
3537
4529
  await createSessionCallback(input);
3538
- await invalidateWorktreeContext?.(input.workspaceId);
3539
- await refresh({ preserveCurrent: true });
4530
+ await refresh({
4531
+ scope: {
4532
+ kind: "workspace",
4533
+ workspaceId: input.workspaceId
4534
+ },
4535
+ preserveCurrent: true
4536
+ });
3540
4537
  } catch (error) {
3541
4538
  if (error instanceof WorktreeSessionBindingError && error.retryable) setPendingSessionBinding({
3542
4539
  ...input,
@@ -3571,8 +4568,13 @@ window.__ModuleLoader__.load({
3571
4568
  openSession
3572
4569
  });
3573
4570
  setPendingSessionBinding(void 0);
3574
- await refresh({ preserveCurrent: true });
3575
- await invalidateWorktreeContext?.(pending.workspaceId);
4571
+ await refresh({
4572
+ scope: {
4573
+ kind: "workspace",
4574
+ workspaceId: pending.workspaceId
4575
+ },
4576
+ preserveCurrent: true
4577
+ });
3576
4578
  } catch (error) {
3577
4579
  if (error instanceof WorktreeSessionBindingError && !error.retryable) setPendingSessionBinding(void 0);
3578
4580
  setActionError(toWorktreeViewError(error));
@@ -3743,12 +4745,35 @@ window.__ModuleLoader__.load({
3743
4745
  className: worktree_css_default.retryButton,
3744
4746
  onClick: () => {
3745
4747
  setActionError(void 0);
3746
- refresh();
4748
+ refresh({ scope: { kind: "global" } });
3747
4749
  },
3748
4750
  children: t("action.retry")
3749
4751
  })
3750
4752
  ]
3751
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
+ }),
3752
4777
  readState.status === "loading" && (0, react_jsx_runtime.jsx)("p", {
3753
4778
  className: worktree_css_default.message,
3754
4779
  children: t("status.loading")
@@ -3765,7 +4790,7 @@ window.__ModuleLoader__.load({
3765
4790
  type: "button",
3766
4791
  className: worktree_css_default.retryButton,
3767
4792
  onClick: () => {
3768
- refresh();
4793
+ refresh({ scope: { kind: "global" } });
3769
4794
  },
3770
4795
  children: t("action.retry")
3771
4796
  })]
@@ -3946,8 +4971,8 @@ window.__ModuleLoader__.load({
3946
4971
  const sessionIds = orderedVisibleWorktreeSessionIds.length === visibleWorktreeSessionIds.length ? orderedVisibleWorktreeSessionIds : visibleWorktreeSessionIds;
3947
4972
  const sessionGroupAutoExpanded = isSessionGroupAutoExpanded(sessionIds, currentSessionId, isCurrentSessionReveal("session-group:" + worktreeGroupKey));
3948
4973
  const sessionGroupExpanded = expandedSessionGroups[worktreeGroupKey] === true || sessionGroupAutoExpanded;
3949
- const state = record.status === "removed" ? "warning" : record.health === "repair" ? "error" : "done";
3950
- const stateLabel = record.status === "removed" ? t("worktree.detached") : record.health === "repair" ? t("worktree.repair") : t("worktree.ready");
4974
+ const state = record.status === "removed" ? "warning" : record.health === "repair" || record.health === "recovery-needed" ? "error" : "done";
4975
+ const stateLabel = record.status === "removed" ? t("worktree.detached") : record.health === "recovery-needed" ? t("worktree.recovery") : record.health === "repair" ? t("worktree.repair") : t("worktree.ready");
3951
4976
  const worktreeExpanded = isWorktreeExpanded(expandSnapshot, record.worktreeId) || isCurrentSessionReveal("worktree:" + record.worktreeId);
3952
4977
  return (0, react_jsx_runtime.jsxs)("div", {
3953
4978
  className: worktree_css_default.worktreeGroup,
@@ -3966,7 +4991,7 @@ window.__ModuleLoader__.load({
3966
4991
  onToggle: () => {
3967
4992
  toggleWorktree(record.worktreeId);
3968
4993
  },
3969
- onCreateSession: record.status === "active" && record.health !== "repair" ? () => {
4994
+ onCreateSession: record.status === "active" && record.health !== "repair" && record.health !== "recovery-needed" ? () => {
3970
4995
  createSession({
3971
4996
  workspaceId: record.workspaceId,
3972
4997
  worktreeId: record.worktreeId,
@@ -3977,13 +5002,13 @@ window.__ModuleLoader__.load({
3977
5002
  open: openWorktreeMenuId === record.worktreeId,
3978
5003
  label: record.branch,
3979
5004
  copyPath: record.absolutePath,
3980
- showCreate: record.status === "active",
3981
- showRemove: record.status === "active",
5005
+ showCreate: record.status === "active" && record.health !== "repair" && record.health !== "recovery-needed",
5006
+ showRemove: record.status === "active" && record.health !== "repair" && record.health !== "recovery-needed",
3982
5007
  disabled: actionPending,
3983
5008
  onOpenChange: (open) => {
3984
5009
  setOpenWorktreeMenuId(open ? record.worktreeId : void 0);
3985
5010
  },
3986
- onCreateWorktree: record.status === "active" ? () => {
5011
+ onCreateWorktree: record.status === "active" && record.health !== "repair" && record.health !== "recovery-needed" ? () => {
3987
5012
  openWorktreeCreator(workspace, {
3988
5013
  baseBranch: record.branch,
3989
5014
  newBranch: createNumberedWorktreeName(record.branch, workspaceWorktreeNames)
@@ -4157,16 +5182,35 @@ window.__ModuleLoader__.load({
4157
5182
  onSubmit: () => {
4158
5183
  if (manager === void 0 || worktreeRemoval === void 0) return;
4159
5184
  const target = worktreeRemoval;
5185
+ const mutationToken = target.mutationToken;
5186
+ if (mutationToken === void 0) {
5187
+ setActionError({
5188
+ code: "WORKTREE_STATE_CONFLICT",
5189
+ message: "",
5190
+ retryable: true,
5191
+ details: {
5192
+ workspaceId: target.workspaceId,
5193
+ worktreeId: target.worktreeId
5194
+ }
5195
+ });
5196
+ return;
5197
+ }
4160
5198
  runMutation(async () => {
4161
5199
  await executeWorktreeAction(manager, {
4162
5200
  type: "removeWorktree",
4163
5201
  input: {
4164
5202
  workspaceId: target.workspaceId,
4165
- worktreeId: target.worktreeId
5203
+ worktreeId: target.worktreeId,
5204
+ mutationToken
4166
5205
  }
4167
5206
  }, permission, onPermissionNotice);
4168
- await invalidateWorktreeContext?.(target.workspaceId);
4169
5207
  setWorktreeRemoval(void 0);
5208
+ }, {
5209
+ scope: {
5210
+ kind: "workspace",
5211
+ workspaceId: target.workspaceId
5212
+ },
5213
+ preserveCurrent: true
4170
5214
  });
4171
5215
  }
4172
5216
  }),
@@ -4176,6 +5220,7 @@ window.__ModuleLoader__.load({
4176
5220
  description: fullAccessConfirmationSnapshot === void 0 ? "" : t("permission.fullAccessDescription", { cwd: fullAccessConfirmationSnapshot.cwd }),
4177
5221
  acknowledgeLabel: t("permission.fullAccessAcknowledge"),
4178
5222
  cancelLabel: t("dialog.cancel"),
5223
+ closeLabel: t("dialog.close"),
4179
5224
  confirmLabel: t("permission.fullAccessEnable"),
4180
5225
  acknowledged: fullAccessAcknowledged,
4181
5226
  onAcknowledgedChange: setFullAccessAcknowledged,
@@ -4216,7 +5261,7 @@ window.__ModuleLoader__.load({
4216
5261
  const record = input.worktrees.find((candidate) => candidate.worktreeId === binding.worktreeId);
4217
5262
  if (record === void 0 || record.workspaceId !== workspace.workspaceId) return none(record === void 0 ? "stale" : "workspace-mismatch");
4218
5263
  if (record.status !== "active") return none("stale");
4219
- if (record.health === "repair") return none("repair");
5264
+ if (record.health === "repair" || record.health === "recovery-needed") return none("repair");
4220
5265
  if (record.branch.length === 0) return none("not-ready");
4221
5266
  return {
4222
5267
  kind: "worktree",
@@ -4251,11 +5296,13 @@ window.__ModuleLoader__.load({
4251
5296
  };
4252
5297
  }
4253
5298
  function identityFrom(sessions, workspaces) {
4254
- const sessionId = sessions.getSnapshot().current;
4255
- 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) };
4256
5303
  return {
4257
5304
  sessionId,
4258
- workspaceId: workspaces.getSnapshot().items.find((candidate) => candidate.sessionIds.includes(sessionId))?.workspaceId
5305
+ workspaceId: workspaceSnapshot.items.find((candidate) => candidate.sessionIds.includes(sessionId))?.workspaceId
4259
5306
  };
4260
5307
  }
4261
5308
  /**
@@ -4274,7 +5321,6 @@ window.__ModuleLoader__.load({
4274
5321
  let scheduleTicket = 0;
4275
5322
  let scheduledCompletion;
4276
5323
  let latestRefresh = Promise.resolve();
4277
- const viewCache = /* @__PURE__ */ new Map();
4278
5324
  let lastObservedIdentity;
4279
5325
  const sameIdentity = (left, right) => left?.sessionId === right.sessionId && left?.workspaceId === right.workspaceId;
4280
5326
  const workspaceTitleFor = (workspaceId) => input.workspaces.getSnapshot().items.find((candidate) => candidate.workspaceId === workspaceId)?.title;
@@ -4311,14 +5357,15 @@ window.__ModuleLoader__.load({
4311
5357
  });
4312
5358
  return;
4313
5359
  }
4314
- const cachedView = viewCache.get(identity.workspaceId);
4315
- 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) {
4316
5363
  store.set({
4317
5364
  status: "ready",
4318
5365
  ...identity.sessionId === void 0 ? {} : { sessionId: identity.sessionId },
4319
5366
  workspaceId: identity.workspaceId,
4320
5367
  workspaceTitle: workspaceTitleFor(identity.workspaceId),
4321
- value: valueFrom(identity, cachedView)
5368
+ value: current.value
4322
5369
  });
4323
5370
  return;
4324
5371
  }
@@ -4347,7 +5394,7 @@ window.__ModuleLoader__.load({
4347
5394
  workspaceId: identity.workspaceId
4348
5395
  };
4349
5396
  try {
4350
- const data = await loadWorktreeView(input.manager, request.workspaceId);
5397
+ const data = await input.viewReader.read(request.workspaceId);
4351
5398
  if (!matchesCurrent(request, requestGeneration)) return;
4352
5399
  const workspace = input.workspaces.getSnapshot().items.find((candidate) => candidate.workspaceId === request.workspaceId);
4353
5400
  if ("error" in data.readiness) {
@@ -4361,7 +5408,6 @@ window.__ModuleLoader__.load({
4361
5408
  });
4362
5409
  return;
4363
5410
  }
4364
- if (data.readiness.status === "ready") viewCache.set(request.workspaceId, data);
4365
5411
  store.set({
4366
5412
  status: "ready",
4367
5413
  ...request.sessionId === void 0 ? {} : { sessionId: request.sessionId },
@@ -4442,6 +5488,8 @@ window.__ModuleLoader__.load({
4442
5488
  if (disposed) return;
4443
5489
  const identity = identityFrom(input.sessions, input.workspaces);
4444
5490
  if (workspaceId !== void 0 && workspaceId !== identity.workspaceId) return;
5491
+ if (identity.workspaceId === void 0) return;
5492
+ input.viewReader.invalidate(identity.workspaceId);
4445
5493
  await refresh();
4446
5494
  await waitForLatestRefresh(workspaceId ?? identity.workspaceId);
4447
5495
  },
@@ -4452,7 +5500,6 @@ window.__ModuleLoader__.load({
4452
5500
  cancelScheduledRefresh();
4453
5501
  unsubscribeSessions();
4454
5502
  unsubscribeWorkspaces();
4455
- viewCache.clear();
4456
5503
  store.set({
4457
5504
  status: "idle",
4458
5505
  value: notReady()
@@ -4464,7 +5511,7 @@ window.__ModuleLoader__.load({
4464
5511
  //#region lib/client/view-mode-store.js
4465
5512
  /** Create one root-scoped, browser-local view-mode store for the two slot entries. */
4466
5513
  function createWorktreeViewStore() {
4467
- return (0, _deepseek_ai_dsh_client_runtime_client.defineStore)({
5514
+ return defineStore({
4468
5515
  init: () => ({ viewMode: "workspace-session" }),
4469
5516
  persist: WORKTREE_VIEW_MODE_STORAGE_KEY,
4470
5517
  actions: { setViewMode: (draft, mode) => {
@@ -4482,54 +5529,85 @@ window.__ModuleLoader__.load({
4482
5529
  }
4483
5530
  return [...bySession.values()];
4484
5531
  }
4485
- function sameWorkspaceItems(left, right) {
4486
- if (left.items.length !== right.items.length) return false;
4487
- return left.items.every((item, index) => {
4488
- const other = right.items[index];
4489
- if (item === other) return true;
4490
- 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;
4491
- const leftSessionIds = item.sessionIds;
4492
- const rightSessionIds = other.sessionIds;
4493
- 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;
4494
5536
  });
4495
5537
  }
4496
5538
  /**
4497
- * Maintains a re-playable in-memory overlay over DSH's Workspace list. Native
4498
- * refreshes are observed and the current sidecar bindings are applied again;
4499
- * 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.
4500
5543
  */
4501
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();
4502
5551
  let bindings = [];
5552
+ let nativeSnapshot = nativeGetSnapshot();
5553
+ let projectedSnapshot = projectVirtualWorkspaceMembership(nativeSnapshot, [], bindings);
4503
5554
  let disposed = false;
4504
- let applying = false;
4505
- const nativeSet = list.set;
4506
- const write = (next) => {
4507
- applying = true;
4508
- try {
4509
- nativeSet(next);
4510
- } finally {
4511
- applying = false;
4512
- }
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;
4513
5564
  };
4514
- list.set = (next) => {
4515
- write(projectVirtualWorkspaceMembership(next, bindings, bindings));
5565
+ const notify = () => {
5566
+ if (disposed) return;
5567
+ if (!refreshSnapshot()) return;
5568
+ for (const listener of [...listeners]) listener();
4516
5569
  };
4517
- const apply = (nextBindings) => {
4518
- const current = list.getSnapshot();
4519
- const next = projectVirtualWorkspaceMembership(current, bindings, nextBindings);
4520
- if (sameWorkspaceItems(current, next)) return;
4521
- write(next);
5570
+ const getSnapshot = () => {
5571
+ if (disposed) return nativeGetSnapshot();
5572
+ refreshSnapshot();
5573
+ return projectedSnapshot;
4522
5574
  };
4523
- const replay = () => {
4524
- if (disposed || applying) return;
4525
- apply(bindings);
5575
+ const subscribe = (listener) => {
5576
+ if (disposed) return () => void 0;
5577
+ listeners.add(listener);
5578
+ return () => listeners.delete(listener);
4526
5579
  };
4527
- 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);
4528
5593
  const sync = (nextBindings) => {
4529
5594
  if (disposed) return;
4530
5595
  const normalized = normalizeBindings(nextBindings);
4531
- apply(normalized);
5596
+ if (sameBindings(bindings, normalized)) return;
5597
+ const previousBindings = bindings;
4532
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);
4533
5611
  };
4534
5612
  return {
4535
5613
  ensure(binding) {
@@ -4543,11 +5621,14 @@ window.__ModuleLoader__.load({
4543
5621
  },
4544
5622
  dispose() {
4545
5623
  if (disposed) return;
4546
- apply([]);
4547
5624
  bindings = [];
5625
+ projectedSnapshot = nativeGetSnapshot();
4548
5626
  disposed = true;
4549
- unsubscribe();
4550
- list.set = nativeSet;
5627
+ for (const listener of [...listeners]) listener();
5628
+ unsubscribeNative();
5629
+ listeners.clear();
5630
+ restoreMethod("getSnapshot", originalGetSnapshot);
5631
+ restoreMethod("subscribe", originalSubscribe);
4551
5632
  }
4552
5633
  };
4553
5634
  }
@@ -4701,6 +5782,31 @@ window.__ModuleLoader__.load({
4701
5782
  }
4702
5783
  //#endregion
4703
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
+ }
4704
5810
  function recoveryKey(sourceSessionId, childSessionId) {
4705
5811
  return `${sourceSessionId}\u0000${childSessionId}`;
4706
5812
  }
@@ -4715,18 +5821,22 @@ window.__ModuleLoader__.load({
4715
5821
  let pending = /* @__PURE__ */ new Map();
4716
5822
  let recoverySnapshot = {
4717
5823
  revision: 0,
4718
- pending: []
5824
+ pending: [],
5825
+ affectedWorkspaceIds: []
4719
5826
  };
4720
5827
  const subscribers = /* @__PURE__ */ new Set();
4721
5828
  const boundChildren = /* @__PURE__ */ new Set();
4722
5829
  const bindingInFlight = /* @__PURE__ */ new Map();
4723
5830
  let reconciliationInFlight;
4724
5831
  let reconciliationAgain = false;
4725
- const publish = () => {
5832
+ let reconciliationForce = false;
5833
+ let lastSessionLineageSignature;
5834
+ const publish = (affectedWorkspaceIds = []) => {
4726
5835
  revision += 1;
4727
5836
  recoverySnapshot = {
4728
5837
  revision,
4729
- pending: [...pending.values()]
5838
+ pending: [...pending.values()],
5839
+ affectedWorkspaceIds: [...new Set(affectedWorkspaceIds)]
4730
5840
  };
4731
5841
  for (const subscriber of subscribers) subscriber();
4732
5842
  };
@@ -4740,30 +5850,44 @@ window.__ModuleLoader__.load({
4740
5850
  ...target === void 0 ? {} : { binding: target },
4741
5851
  error
4742
5852
  });
4743
- publish();
5853
+ publish(target === void 0 ? [] : [target.workspaceId]);
4744
5854
  };
4745
5855
  const clearRecovery = (sourceSessionId, childSessionId) => {
4746
5856
  const key = recoveryKey(sourceSessionId, childSessionId);
4747
- if (!pending.has(key)) return;
5857
+ const current = pending.get(key);
5858
+ if (current === void 0) return { cleared: false };
4748
5859
  const next = new Map(pending);
4749
5860
  next.delete(key);
4750
5861
  pending = next;
4751
- publish();
5862
+ return {
5863
+ cleared: true,
5864
+ workspaceId: current.binding?.workspaceId
5865
+ };
4752
5866
  };
4753
- const attemptBinding = async (sourceSessionId, childSessionId) => {
4754
- if (disposed || boundChildren.has(childSessionId)) return { bound: false };
4755
- let target;
5867
+ const lookupBinding = async (sourceSessionId) => {
4756
5868
  try {
4757
- target = await options.findBinding(sourceSessionId);
5869
+ return (await options.findBindings([sourceSessionId])).bySessionId.get(sourceSessionId) ?? { status: "missing" };
4758
5870
  } catch (error) {
4759
- 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);
4760
5882
  return { bound: false };
4761
5883
  }
4762
5884
  if (disposed) return { bound: false };
4763
- if (target === void 0 || target.status !== "active") {
4764
- 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]);
4765
5888
  return { bound: false };
4766
5889
  }
5890
+ const target = lookup.binding;
4767
5891
  try {
4768
5892
  await options.bindSession({
4769
5893
  workspaceId: target.workspaceId,
@@ -4778,50 +5902,64 @@ window.__ModuleLoader__.load({
4778
5902
  status: "active"
4779
5903
  };
4780
5904
  boundChildren.add(childSessionId);
4781
- clearRecovery(sourceSessionId, childSessionId);
5905
+ const { workspaceId: previousWorkspaceId } = clearRecovery(sourceSessionId, childSessionId);
4782
5906
  options.onBound?.(childBinding);
4783
- publish();
5907
+ publish([target.workspaceId, ...previousWorkspaceId === void 0 ? [] : [previousWorkspaceId]]);
4784
5908
  return { bound: true };
4785
5909
  } catch (error) {
4786
5910
  setRecovery(sourceSessionId, childSessionId, error, target);
4787
5911
  return { bound: false };
4788
5912
  }
4789
5913
  };
4790
- const bindChild = (sourceSessionId, childSessionId) => {
5914
+ const bindChild = (sourceSessionId, childSessionId, providedLookup) => {
4791
5915
  if (disposed || boundChildren.has(childSessionId)) return Promise.resolve({ bound: false });
4792
5916
  const key = recoveryKey(sourceSessionId, childSessionId);
4793
5917
  const current = bindingInFlight.get(key);
4794
5918
  if (current !== void 0) return current;
4795
- const promise = attemptBinding(sourceSessionId, childSessionId).finally(() => {
5919
+ const promise = attemptBinding(sourceSessionId, childSessionId, providedLookup).finally(() => {
4796
5920
  if (bindingInFlight.get(key) === promise) bindingInFlight.delete(key);
4797
5921
  });
4798
5922
  bindingInFlight.set(key, promise);
4799
5923
  return promise;
4800
5924
  };
4801
- const reconcileNow = async () => {
5925
+ const reconcileNow = async (force) => {
4802
5926
  if (disposed || options.sessions === void 0) return;
4803
- const snapshot = options.sessions.getSnapshot();
4804
- if (snapshot.phase === "pending") return;
4805
- if (!Array.isArray(snapshot.ids) || typeof snapshot.byId !== "object" || snapshot.byId === null) return;
4806
- const candidates = snapshot.ids.flatMap((childSessionId) => {
4807
- const summary = snapshot.byId[childSessionId];
4808
- if (summary?.parentId === void 0 || summary.parentId === childSessionId || summary.blank === true || summary.origin === "subagent" || snapshot.byId[summary.parentId] === void 0) return [];
4809
- return [{
4810
- childSessionId,
4811
- sourceSessionId: summary.parentId
4812
- }];
4813
- });
4814
- 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)));
4815
5947
  };
4816
- const reconcile = () => {
5948
+ const reconcile = (input = {}) => {
5949
+ const force = input.force === true;
4817
5950
  if (reconciliationInFlight !== void 0) {
4818
5951
  reconciliationAgain = true;
5952
+ reconciliationForce ||= force;
4819
5953
  return reconciliationInFlight;
4820
5954
  }
5955
+ let nextForce = force;
4821
5956
  const run = async () => {
4822
5957
  do {
5958
+ const forceThisPass = nextForce || reconciliationForce;
5959
+ nextForce = false;
5960
+ reconciliationForce = false;
4823
5961
  reconciliationAgain = false;
4824
- await reconcileNow();
5962
+ await reconcileNow(forceThisPass);
4825
5963
  } while (!disposed && reconciliationAgain);
4826
5964
  };
4827
5965
  const promise = run().finally(() => {
@@ -4849,7 +5987,11 @@ window.__ModuleLoader__.load({
4849
5987
  async retry(key) {
4850
5988
  const item = pending.get(key);
4851
5989
  if (item === void 0 || disposed) return false;
4852
- 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;
4853
5995
  },
4854
5996
  dispose() {
4855
5997
  disposed = true;
@@ -4860,27 +6002,56 @@ window.__ModuleLoader__.load({
4860
6002
  }
4861
6003
  //#endregion
4862
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
+ }
4863
6031
  /** Required DSH Client services; Connection is the sole Worktree wire dependency. */
4864
6032
  const inject = [
4865
6033
  "connection",
4866
6034
  "locale",
4867
6035
  "slots",
4868
6036
  "sessions",
4869
- "workspaces"
6037
+ "workspaces",
6038
+ "uiWorkspace"
4870
6039
  ];
4871
6040
  /**
4872
6041
  * DSH Client entry. The adapter is composed once per plugin fiber and is disposed
4873
6042
  * with that fiber, so slot consumers share one manager and one request lifetime.
4874
6043
  */
4875
6044
  function apply(ctx) {
6045
+ const locale = ctx.locale;
4876
6046
  if (typeof document !== "undefined") ctx.effect(() => installWorktreePermissionIcon(document), "clutch-dsh-worktree: permission icon cleanup");
4877
- ctx.effect(() => ctx.locale.register(WORKTREE_NS, {
6047
+ ctx.effect(() => locale.register(WORKTREE_NS, {
4878
6048
  zh,
4879
6049
  en
4880
6050
  }), "clutch-dsh-worktree: locale dictionaries");
4881
6051
  const manager = createWorktreeConnectionAdapter(ctx.connection.rpc);
6052
+ const viewReader = createWorktreeViewReader(manager);
4882
6053
  const fullAccessConfirmation = createWorktreeFullAccessConfirmationController();
4883
- const permissionNotice = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(void 0);
6054
+ const permissionNotice = createSnapshotStore(void 0);
4884
6055
  const permissionManager = typeof document !== "undefined" ? manager : void 0;
4885
6056
  const reportPermissionNotice = (input, result) => {
4886
6057
  const visible = result.status === "fallback-workspace-write" || result.status === "user-restricted" || result.status === "unverified";
@@ -4890,21 +6061,23 @@ window.__ModuleLoader__.load({
4890
6061
  } : void 0);
4891
6062
  };
4892
6063
  const sessions = ctx.sessions;
6064
+ const slots = ctx.slots;
4893
6065
  const virtualWorkspaceMembership = createVirtualWorkspaceMembership(ctx.workspaces.list);
4894
6066
  const contextProjection = createWorktreeContextProjection({
4895
6067
  sessions: ctx.sessions.list,
4896
6068
  workspaces: ctx.workspaces.list,
4897
- manager,
4898
- storeFactory: _deepseek_ai_dsh_client_runtime_client.createSnapshotStore
6069
+ viewReader,
6070
+ storeFactory: createSnapshotStore
4899
6071
  });
4900
6072
  ctx.effect(() => () => manager.dispose(), "clutch-dsh-worktree: connection cleanup");
6073
+ ctx.effect(() => () => viewReader.dispose(), "clutch-dsh-worktree: view reader cleanup");
4901
6074
  ctx.effect(() => () => fullAccessConfirmation.dispose(), "clutch-dsh-worktree: Full Access confirmation cleanup");
4902
6075
  ctx.effect(() => () => virtualWorkspaceMembership.dispose(), "clutch-dsh-worktree: Workspace membership cleanup");
4903
6076
  ctx.effect(() => () => contextProjection.dispose(), "clutch-dsh-worktree: Session context cleanup");
4904
6077
  contextProjection.refresh();
4905
6078
  const viewStore = createWorktreeViewStore();
4906
- const expandState = createWorktreeExpandStateStore(_deepseek_ai_dsh_client_runtime_client.createSnapshotStore);
4907
- const sessionOrder = createWorktreeSessionOrderStore(_deepseek_ai_dsh_client_runtime_client.createSnapshotStore);
6079
+ const expandState = createWorktreeExpandStateStore(createSnapshotStore);
6080
+ const sessionOrder = createWorktreeSessionOrderStore(createSnapshotStore);
4908
6081
  ctx.effect(() => () => sessionOrder.dispose(), "clutch-dsh-worktree: Session order cleanup");
4909
6082
  const ensureSessionWorkspace = (workspaceId, sessionId) => {
4910
6083
  virtualWorkspaceMembership.ensure({
@@ -4917,19 +6090,64 @@ window.__ModuleLoader__.load({
4917
6090
  };
4918
6091
  const forkableSessions = ctx.sessions;
4919
6092
  const nativeFork = forkableSessions.fork;
4920
- const findWorktreeSessionBinding = async (sessionId) => {
4921
- const workspaceIds = ctx.workspaces.list.getSnapshot().items.map((workspace) => workspace.workspaceId);
4922
- const results = await Promise.allSettled(workspaceIds.map(async (workspaceId) => {
4923
- return (await manager.listBindings({ workspaceId })).find((binding) => binding.sessionId === sessionId && binding.status === "active");
4924
- }));
4925
- const found = results.find((result) => result.status === "fulfilled" && result.value !== void 0);
4926
- if (found !== void 0) return found.value;
4927
- const failed = results.find((result) => result.status === "rejected");
4928
- 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 };
4929
6147
  };
4930
6148
  const forkCoordinator = typeof nativeFork !== "function" ? void 0 : createWorktreeSessionForkCoordinator({
4931
6149
  fork: (input) => nativeFork.call(ctx.sessions, input),
4932
- findBinding: findWorktreeSessionBinding,
6150
+ findBindings: findWorktreeSessionBindings,
4933
6151
  bindSession: (input) => manager.bindSession(input),
4934
6152
  sessions: ctx.sessions.list
4935
6153
  });
@@ -4938,8 +6156,15 @@ window.__ModuleLoader__.load({
4938
6156
  const reconcileForkChildren = () => {
4939
6157
  forkCoordinator.reconcile();
4940
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
+ };
4941
6166
  const unsubscribeSessionList = ctx.sessions.list.subscribe(reconcileForkChildren);
4942
- const unsubscribeWorkspaceList = ctx.workspaces.list.subscribe(reconcileForkChildren);
6167
+ const unsubscribeWorkspaceList = ctx.workspaces.list.subscribe(reconcileForkChildrenForWorkspace);
4943
6168
  ctx.effect(() => () => {
4944
6169
  unsubscribeSessionList();
4945
6170
  unsubscribeWorkspaceList();
@@ -4951,7 +6176,7 @@ window.__ModuleLoader__.load({
4951
6176
  const worktreeSessionConnector = createWorktreeSessionConnector({
4952
6177
  manager,
4953
6178
  sessions: ctx.sessions.list,
4954
- archivedSessionIds: () => ctx.workspaces.list.getSnapshot().archivedSessionIds ?? [],
6179
+ archivedSessionIds: () => ctx.workspaces.list.getSnapshot().archivedSessionIds,
4955
6180
  createSession: async (input) => String(await sessions.create(input)),
4956
6181
  ensureSessionWorkspace,
4957
6182
  permission: permissionManager,
@@ -4962,21 +6187,21 @@ window.__ModuleLoader__.load({
4962
6187
  }
4963
6188
  });
4964
6189
  ctx.effect(() => () => worktreeSessionConnector.dispose(), "clutch-dsh-worktree: Worktree Session connector cleanup");
4965
- ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
6190
+ slots.inject("conversation.session.header.actions", () => slots.register({
4966
6191
  name: "conversation.session.header.actions",
4967
6192
  id: "clutch-dsh-worktree-context-header",
4968
6193
  order: -5,
4969
6194
  locale: WORKTREE_NS,
4970
6195
  inject: () => ({ hooks: { worktreeContext: contextProjection.store } })
4971
6196
  }, WorktreeHeaderContext));
4972
- ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
6197
+ slots.inject("sidebar.footer.action", () => slots.register({
4973
6198
  name: "sidebar.footer.action",
4974
6199
  id: "clutch-dsh-worktree-mode-action",
4975
6200
  store: viewStore,
4976
6201
  locale: WORKTREE_NS,
4977
6202
  inject: () => ({ available: true })
4978
6203
  }, WorktreeModeAction));
4979
- ctx.slots.inject("shell.overlay", () => ctx.slots.register({
6204
+ slots.inject("shell.overlay", () => slots.register({
4980
6205
  name: "shell.overlay",
4981
6206
  id: "clutch-dsh-worktree-navigation",
4982
6207
  store: viewStore,
@@ -4987,6 +6212,7 @@ window.__ModuleLoader__.load({
4987
6212
  sessionOrder,
4988
6213
  hooks: { worktreeContext: contextProjection.store },
4989
6214
  manager,
6215
+ viewReader,
4990
6216
  permission: permissionManager,
4991
6217
  confirmFullAccess: permissionManager === void 0 ? void 0 : fullAccessConfirmation.request,
4992
6218
  fullAccessConfirmation: typeof document === "undefined" ? void 0 : fullAccessConfirmation,
@@ -4994,13 +6220,13 @@ window.__ModuleLoader__.load({
4994
6220
  onPermissionNotice: reportPermissionNotice,
4995
6221
  permissionNotice,
4996
6222
  createWorkspace: async () => {
4997
- const workspacePath = await ctx.workspaces.pickDirectory();
6223
+ const workspacePath = await ctx.uiWorkspace.pickDirectory();
4998
6224
  if (workspacePath !== null) await ctx.workspaces.create({ path: workspacePath });
4999
6225
  },
5000
6226
  createSessionForWorktree: (input) => worktreeSessionConnector.create(input),
5001
6227
  invalidateWorktreeContext: (workspaceId) => contextProjection.invalidate(workspaceId),
5002
6228
  createMainSession: (workspaceId) => {
5003
- ctx.workspaces.startSession(workspaceId);
6229
+ ctx.uiWorkspace.startSession(workspaceId);
5004
6230
  },
5005
6231
  renameWorkspace: async (workspaceId, title) => {
5006
6232
  await ctx.workspaces.rename(workspaceId, title);