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