dsh-git-worktree 0.10.0 → 0.11.0
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/CHANGELOG.md +41 -1
- package/README.en.md +7 -4
- package/README.md +7 -4
- package/lib/adapters/registry.js +4 -32
- package/lib/adapters/registry.js.map +1 -1
- package/lib/client/actions.d.ts +2 -0
- package/lib/client/pre-session/controller.js +5 -0
- package/lib/client/pre-session/controller.js.map +1 -1
- package/lib/client/review-console/PreflightStatus.js +5 -2
- package/lib/client/review-console/PreflightStatus.js.map +1 -1
- package/lib/client/review-console/ReviewActions.js +47 -46
- package/lib/client/review-console/ReviewActions.js.map +1 -1
- package/lib/client/review-console/ReviewDetailsModal.js +13 -3
- package/lib/client/review-console/ReviewDetailsModal.js.map +1 -1
- package/lib/client/review-console/review-console.styles.js +22 -11
- package/lib/client/review-console/review-console.styles.js.map +1 -1
- package/lib/client/target-console/WorktreeReviewStatus.js +7 -7
- package/lib/client/target-console/WorktreeReviewStatus.js.map +1 -1
- package/lib/client/workspace-sidebar/index.js +6 -3
- package/lib/client/workspace-sidebar/index.js.map +1 -1
- package/lib/client.js +1461 -467
- package/lib/commit-message.d.ts +2 -0
- package/lib/commit-message.js +5 -0
- package/lib/commit-message.js.map +1 -0
- package/lib/console-host/control-plane.js +6 -5
- package/lib/console-host/control-plane.js.map +1 -1
- package/lib/console-remote/schemas.d.ts +1 -1
- package/lib/console-remote/schemas.js +2 -1
- package/lib/console-remote/schemas.js.map +1 -1
- package/lib/host-compat.js +2 -1
- package/lib/host-compat.js.map +1 -1
- package/lib/i18n/client-messages.d.ts +8 -4
- package/lib/i18n/client-messages.js +2 -4
- package/lib/i18n/client-messages.js.map +1 -1
- package/lib/i18n/host-messages.d.ts +3 -7
- package/lib/i18n/host-messages.js +3 -7
- package/lib/i18n/host-messages.js.map +1 -1
- package/lib/index.d.ts +9 -9
- package/lib/ports.d.ts +1 -1
- package/lib/session-checkout-apply.js +6 -5
- package/lib/session-checkout-apply.js.map +1 -1
- package/lib/session-checkout-module.js +10 -7
- package/lib/session-checkout-module.js.map +1 -1
- package/lib/workspace-provider-lifecycle.js +31 -6
- package/lib/workspace-provider-lifecycle.js.map +1 -1
- package/package.json +43 -41
- package/scripts/check-publish.mjs +2 -0
- package/scripts/workspace-sidebar-upstream-alpha.mjs +16 -14
- package/scripts/workspace-sidebar-upstream-next.mjs +12 -16
- package/scripts/workspace-sidebar-upstream.mjs +18 -4
package/lib/client.js
CHANGED
|
@@ -136,6 +136,14 @@ const clientMessages = {
|
|
|
136
136
|
"zh": "未提供验证记录。",
|
|
137
137
|
"en": "No validation records provided."
|
|
138
138
|
},
|
|
139
|
+
"detail.expandList": {
|
|
140
|
+
"zh": "展开全部 {count} 项",
|
|
141
|
+
"en": "Show all {count} items"
|
|
142
|
+
},
|
|
143
|
+
"detail.collapseList": {
|
|
144
|
+
"zh": "收起",
|
|
145
|
+
"en": "Show fewer"
|
|
146
|
+
},
|
|
139
147
|
"detail.version": {
|
|
140
148
|
"zh": "版本信息",
|
|
141
149
|
"en": "Version information"
|
|
@@ -188,10 +196,6 @@ const clientMessages = {
|
|
|
188
196
|
"zh": "当前会话已切换,已停止准备独立工作目录。",
|
|
189
197
|
"en": "The current session changed. Isolated working directory preparation stopped."
|
|
190
198
|
},
|
|
191
|
-
"500": {
|
|
192
|
-
"zh": "/500",
|
|
193
|
-
"en": "/500"
|
|
194
|
-
},
|
|
195
199
|
"the.cwd.of.new.harness.session.does.not": {
|
|
196
200
|
"zh": "Harness 新建 Session {p0} 的 cwd 与 Host 记录不一致。",
|
|
197
201
|
"en": "The cwd of new Harness Session {p0} does not match the Host record."
|
|
@@ -6185,6 +6189,13 @@ function superRefine(fn, params) {
|
|
|
6185
6189
|
const describe = describe$1;
|
|
6186
6190
|
const meta = meta$1;
|
|
6187
6191
|
|
|
6192
|
+
//#endregion
|
|
6193
|
+
//#region src/commit-message.ts
|
|
6194
|
+
/** Commit bodies are sent to Git on stdin; 500 characters is not a Git limit. */
|
|
6195
|
+
function isValidCommitMessage(value) {
|
|
6196
|
+
return typeof value === "string" && value.trim().length > 0 && !value.includes("\0");
|
|
6197
|
+
}
|
|
6198
|
+
|
|
6188
6199
|
//#endregion
|
|
6189
6200
|
//#region src/types.ts
|
|
6190
6201
|
const SESSION_CHECKOUT_ERROR_CODES = [
|
|
@@ -6414,7 +6425,7 @@ const strict = (shape) => object(shape).strict();
|
|
|
6414
6425
|
const sessionIdSchema = string().min(1).max(200).refine((value) => !/[\0\r\n]/u.test(value), "unsafe session id");
|
|
6415
6426
|
const checkoutIdSchema = string().min(1).max(200).refine((value) => !value.includes("..") && !/[\\/\0\r\n]/u.test(value), "unsafe checkout id");
|
|
6416
6427
|
const reviewIdSchema = string().min(1).max(200).refine((value) => !/[\0\r\n]/u.test(value), "unsafe review id");
|
|
6417
|
-
const commitMessageSchema = string().trim().
|
|
6428
|
+
const commitMessageSchema = string().trim().refine(isValidCommitMessage, "invalid commit message");
|
|
6418
6429
|
const revisionSchema = number().int().nonnegative();
|
|
6419
6430
|
const gitOidSchema = string().regex(/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/iu);
|
|
6420
6431
|
const oidSchema = union([
|
|
@@ -8722,7 +8733,6 @@ const REVIEW_CONSOLE_STYLES = String.raw`
|
|
|
8722
8733
|
.dsh-wt-retention-select { display:grid; gap:5px; padding:9px; border-radius:8px; background:var(--wt-panel); font-size:12px; }
|
|
8723
8734
|
.dsh-wt-retention-select select { min-height:32px; border:1px solid var(--wt-line); border-radius:7px; padding:0 8px; background:Canvas; color:inherit; }
|
|
8724
8735
|
.dsh-wt-preflight { display:grid; gap:7px; margin-top:7px; padding:8px 9px; border-radius:8px; background:var(--wt-panel); color:var(--wt-muted); font-size:12px; }
|
|
8725
|
-
.dsh-wt-preflight[data-preflight="conflict"],
|
|
8726
8736
|
.dsh-wt-preflight[data-preflight="blocked"],
|
|
8727
8737
|
.dsh-wt-preflight[data-preflight="error"] { color:var(--wt-amber); }
|
|
8728
8738
|
.dsh-wt-preflight-head { display:flex; align-items:center; justify-content:space-between; gap:8px; }
|
|
@@ -8735,7 +8745,15 @@ const REVIEW_CONSOLE_STYLES = String.raw`
|
|
|
8735
8745
|
.dsh-wt-delivery-proof dt { color:var(--wt-muted); }
|
|
8736
8746
|
.dsh-wt-preflight-facts dd,
|
|
8737
8747
|
.dsh-wt-delivery-proof dd { min-width:0; margin:0; overflow-wrap:anywhere; }
|
|
8738
|
-
.dsh-wt-conflict
|
|
8748
|
+
.dsh-wt-preflight.dsh-wt-conflict { display:flex; align-items:center; flex-wrap:wrap; color:inherit; min-width:0; padding:8px 10px; gap:8px 12px; border:1px solid color-mix(in srgb, var(--wt-amber) 22%, transparent); background:color-mix(in srgb, var(--wt-amber) 5%, transparent); }
|
|
8749
|
+
.dsh-wt-conflict-heading { display:flex; align-items:center; flex:1 1 auto; gap:8px; min-width:0; }
|
|
8750
|
+
.dsh-wt-conflict-heading > div { display:flex; align-items:center; flex-wrap:wrap; gap:2px 10px; min-width:0; }
|
|
8751
|
+
.dsh-wt-conflict-heading > .dsh-wt-icon,
|
|
8752
|
+
.dsh-wt-conflict-heading strong { color:var(--wt-amber); }
|
|
8753
|
+
.dsh-wt-conflict-heading strong { line-height:1.5; overflow-wrap:anywhere; }
|
|
8754
|
+
.dsh-wt-conflict-heading p { margin:0; color:var(--wt-muted); line-height:1.5; }
|
|
8755
|
+
.dsh-wt-conflict-actions { display:flex; flex-wrap:wrap; justify-content:flex-end; gap:8px; margin-left:auto; color:var(--wt-ink); }
|
|
8756
|
+
.dsh-wt-conflict-actions .dsh-wt-button { display:inline-flex; align-items:center; gap:6px; max-width:100%; }
|
|
8739
8757
|
.dsh-wt-recovery-actions { display:flex; flex-wrap:wrap; gap:6px; }
|
|
8740
8758
|
.dsh-wt-inline-action { border:0; padding:0; background:transparent; color:inherit; font:inherit; text-decoration:underline; cursor:pointer; }
|
|
8741
8759
|
.dsh-wt-inline-action:disabled { opacity:.5; cursor:not-allowed; }
|
|
@@ -8745,18 +8763,21 @@ const REVIEW_CONSOLE_STYLES = String.raw`
|
|
|
8745
8763
|
.dsh-wt-delivery-proof-compact { display:block; margin:1px 0 0; padding:0; border:0; background:transparent; color:var(--wt-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
8746
8764
|
.dsh-wt-action-status { min-height:1.35em; margin-top:7px; color:var(--wt-muted); font-size:12px; }
|
|
8747
8765
|
.dsh-wt-review-dock { box-sizing:border-box; display:flex; flex:none; align-items:center; gap:9px; width:calc(100% - 2 * var(--dsh-composer-side-clearance, 16px) - 2 * var(--dsh-composer-dock-inset, 0px)); max-width:calc(var(--dsh-composer-card-max-width, 780px) - 2 * var(--dsh-composer-dock-inset, 0px)); margin:0 auto 8px; padding:7px 9px; border:1px solid color-mix(in srgb, #3275db 22%, transparent); border-radius:9px; background:color-mix(in srgb, #3275db 6%, transparent); color:var(--wt-ink); font-size:12px; }
|
|
8748
|
-
.dsh-wt-review-dock > .dsh-wt-icon { order:-2; }
|
|
8749
|
-
.dsh-wt-review-dock-copy {
|
|
8766
|
+
.dsh-wt-review-dock > .dsh-wt-icon { order:-2; align-self:flex-start; margin-top:6px; }
|
|
8767
|
+
.dsh-wt-review-dock-copy { display:grid; min-width:0; flex:1; gap:1px; }
|
|
8750
8768
|
.dsh-wt-review-dock-copy strong { font-weight:500; overflow-wrap:anywhere; }
|
|
8751
8769
|
.dsh-wt-review-dock-copy span { color:var(--wt-muted); font-size:12px; }
|
|
8752
|
-
.dsh-wt-review-dock .dsh-wt-review-actions { min-width:0; max-width:100%; padding:0; }
|
|
8770
|
+
.dsh-wt-review-dock .dsh-wt-review-actions { flex:1; min-width:0; max-width:100%; padding:0; }
|
|
8771
|
+
.dsh-wt-review-action-head { display:flex; align-items:center; flex-wrap:wrap; gap:6px 10px; min-width:0; }
|
|
8772
|
+
.dsh-wt-review-action-head > .dsh-wt-review-dock-copy { flex:1 1 180px; }
|
|
8773
|
+
.dsh-wt-review-action-head > .dsh-wt-actions { flex:0 0 auto; margin-left:auto; }
|
|
8753
8774
|
.dsh-wt-action-status:empty { min-height:0; margin-top:0; }
|
|
8754
8775
|
.dsh-wt-action-status:empty { min-height:0; margin-top:0; }
|
|
8755
8776
|
.dsh-wt-review-dock .dsh-wt-action-status:empty { display:none; }
|
|
8756
8777
|
.dsh-wt-review-evidence-status { margin:0 14px 10px 42px; color:var(--wt-muted); font-size:12px; }
|
|
8757
8778
|
.dsh-wt-review-dock .dsh-wt-actions { justify-content:flex-end; }
|
|
8758
8779
|
.dsh-wt-review-dock .dsh-wt-preflight-facts { display:none; }
|
|
8759
|
-
.dsh-wt-review-dock .dsh-wt-preflight { margin:0; padding:
|
|
8780
|
+
.dsh-wt-review-dock .dsh-wt-preflight { margin:8px 0 0; padding:8px 10px; }
|
|
8760
8781
|
.dsh-wt-review-dock .dsh-wt-preflight[data-preflight="loading"],
|
|
8761
8782
|
.dsh-wt-review-dock .dsh-wt-preflight[data-preflight="ready"],
|
|
8762
8783
|
.dsh-wt-review-dock .dsh-wt-preflight[data-preflight="local_advanced"],
|
|
@@ -8771,16 +8792,13 @@ const REVIEW_CONSOLE_STYLES = String.raw`
|
|
|
8771
8792
|
.dsh-wt-review-validation-details,
|
|
8772
8793
|
.dsh-wt-review-actions { margin-left:0; padding-left:14px; }
|
|
8773
8794
|
.dsh-wt-review-dock { flex-wrap:wrap; width:calc(100% - 2 * var(--dsh-composer-side-clearance, 12px) - 2 * var(--dsh-composer-dock-inset, 0px)); }
|
|
8774
|
-
.dsh-wt-review-dock > .dsh-wt-
|
|
8775
|
-
.dsh-wt-review-dock-copy { order:-1; order:-1; flex-basis:calc(100% - 28px); }
|
|
8776
|
-
|
|
8777
|
-
.dsh-wt-review-dock .dsh-wt-review-actions { margin-left:auto; }
|
|
8795
|
+
.dsh-wt-review-dock > .dsh-wt-review-dock-copy { flex-basis:calc(100% - 28px); }
|
|
8778
8796
|
}
|
|
8779
8797
|
|
|
8780
8798
|
.dsh-wt-icon { display:inline-flex; width:18px; height:18px; flex:0 0 18px; vertical-align:middle; }
|
|
8781
8799
|
.dsh-wt-review-dock { background:var(--dsw-alias-bg-layer-2, #fff); border-color:var(--wt-line); padding:10px 12px; gap:10px; }
|
|
8782
8800
|
.dsh-wt-review-dock-copy strong { font-size:13px; font-weight:550; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
8783
|
-
.dsh-wt-review-dock-copy .dsh-wt-dock-evidence { display:flex; align-items:center; gap:5px; }
|
|
8801
|
+
.dsh-wt-review-dock-copy .dsh-wt-dock-evidence { display:flex; align-items:center; flex-wrap:wrap; gap:5px; }
|
|
8784
8802
|
.dsh-wt-dock-evidence .dsh-wt-icon { width:14px; height:14px; flex-basis:14px; }
|
|
8785
8803
|
.dsh-wt-details-trigger { display:inline-flex; align-items:center; gap:5px; flex-shrink:0; padding:6px; border:0; background:transparent; color:inherit; font:inherit; cursor:pointer; border-radius:6px; }
|
|
8786
8804
|
.dsh-wt-details-trigger:hover { background:var(--wt-panel); }
|
|
@@ -8797,6 +8815,10 @@ const REVIEW_CONSOLE_STYLES = String.raw`
|
|
|
8797
8815
|
.dsh-wt-details-notice[data-tone="warning"] { background:color-mix(in srgb, var(--wt-amber) 8%, transparent); }
|
|
8798
8816
|
.dsh-wt-details-section { border-top:1px solid var(--wt-line); padding:16px 0; }
|
|
8799
8817
|
.dsh-wt-details-section h3 { font-size:14px; font-weight:600; margin:0 0 12px; }
|
|
8818
|
+
.dsh-wt-details-list-toggle { display:inline-flex; align-items:center; gap:6px; margin-top:8px; padding:4px 0; border:0; background:transparent; color:var(--wt-muted); font:inherit; cursor:pointer; }
|
|
8819
|
+
.dsh-wt-details-list-toggle:hover { color:var(--wt-ink); }
|
|
8820
|
+
.dsh-wt-details-list-toggle:focus-visible { outline:2px solid #5a8dee; outline-offset:3px; }
|
|
8821
|
+
.dsh-wt-details-list-toggle[aria-expanded="true"] .dsh-wt-icon { transform:rotate(90deg); }
|
|
8800
8822
|
.dsh-wt-details-files, .dsh-wt-details-tests { padding:0; margin:0; list-style:none; }
|
|
8801
8823
|
.dsh-wt-details-files li { display:flex; align-items:flex-start; gap:10px; padding:8px 0; }
|
|
8802
8824
|
.dsh-wt-details-files li > span:nth-child(2) { flex:1; min-width:0; overflow-wrap:anywhere; font-family:ui-monospace, monospace; }
|
|
@@ -9064,6 +9086,7 @@ var PreSessionWorktreeController = class {
|
|
|
9064
9086
|
if (request.input.phase !== "plain") throw new PreSessionWorktreeError(t("the.draft.is.being.submitted.or.parsed.wait"));
|
|
9065
9087
|
if (request.input.occurrences.length > 0) throw new PreSessionWorktreeError(t("the.draft.contains.unserialized.references.remove.the.reference"));
|
|
9066
9088
|
if (!this.services.uiWorkspace?.openSession && !this.services.sessions.open) throw new PreSessionWorktreeError(t("harness.session.navigation.unavailable"));
|
|
9089
|
+
const sourcePreset = (this.services.sessions.list.getSnapshot().byId[request.sessionId]?.projectionValues)?.agentPreset;
|
|
9067
9090
|
const previousBlock = this.services.conversation.blocks.storeFor(request.sessionId).getSnapshot();
|
|
9068
9091
|
this.services.conversation.blocks.set(request.sessionId, { reason: t("creating.isolated.worktree") });
|
|
9069
9092
|
let created;
|
|
@@ -9082,7 +9105,8 @@ var PreSessionWorktreeController = class {
|
|
|
9082
9105
|
workspaceId = workspace.workspaceId;
|
|
9083
9106
|
actualSessionId = await this.services.sessions.create({
|
|
9084
9107
|
workspaceId: workspace.workspaceId,
|
|
9085
|
-
sessionId: created.targetSessionId
|
|
9108
|
+
sessionId: created.targetSessionId,
|
|
9109
|
+
...typeof sourcePreset === "string" ? { agentPreset: sourcePreset } : {}
|
|
9086
9110
|
});
|
|
9087
9111
|
if (actualSessionId !== created.targetSessionId) throw new PreSessionWorktreeError(t("harness.created.unexpected.session.expected.2", {
|
|
9088
9112
|
p0: actualSessionId,
|
|
@@ -10325,6 +10349,28 @@ function validationText(status, t) {
|
|
|
10325
10349
|
function validationIcon(status) {
|
|
10326
10350
|
return status === "passed" ? "check" : status === "failed" || status === "partial" ? "warning" : "minus";
|
|
10327
10351
|
}
|
|
10352
|
+
const COLLAPSED_LIST_LIMIT = 5;
|
|
10353
|
+
function ReviewDetailsList({ label, className, items }) {
|
|
10354
|
+
const t = useClientTranslator();
|
|
10355
|
+
const listId = (0, react.useId)();
|
|
10356
|
+
const [expanded, setExpanded] = (0, react.useState)(false);
|
|
10357
|
+
const collapsible = items.length > COLLAPSED_LIST_LIMIT;
|
|
10358
|
+
const toggleText = expanded ? t("detail.collapseList") : t("detail.expandList", { count: items.length });
|
|
10359
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
10360
|
+
id: listId,
|
|
10361
|
+
className,
|
|
10362
|
+
"aria-label": label,
|
|
10363
|
+
children: expanded ? items : items.slice(0, COLLAPSED_LIST_LIMIT)
|
|
10364
|
+
}), collapsible ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10365
|
+
type: "button",
|
|
10366
|
+
className: "dsh-wt-details-list-toggle",
|
|
10367
|
+
"aria-label": `${label}: ${toggleText}`,
|
|
10368
|
+
"aria-expanded": expanded,
|
|
10369
|
+
"aria-controls": listId,
|
|
10370
|
+
onClick: () => setExpanded((value) => !value),
|
|
10371
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "chevron" }), toggleText]
|
|
10372
|
+
}) : null] });
|
|
10373
|
+
}
|
|
10328
10374
|
function ReviewDetailsModal({ open, onClose, target, preflight }) {
|
|
10329
10375
|
const t = useClientTranslator();
|
|
10330
10376
|
const content = (0, react.useRef)(null);
|
|
@@ -10356,6 +10402,7 @@ function ReviewDetailsModal({ open, onClose, target, preflight }) {
|
|
|
10356
10402
|
}, [open]);
|
|
10357
10403
|
const review = target.review;
|
|
10358
10404
|
if (!review) return null;
|
|
10405
|
+
const listKey = `${target.checkoutId}:${review.reviewId}:${target.revision}:${open}`;
|
|
10359
10406
|
const conflict = preflight?.status === "conflict";
|
|
10360
10407
|
const recovery = target.state === "preview_detached" || target.state === "recovery_required";
|
|
10361
10408
|
const state = recovery ? "detail.recovery" : conflict || preflight?.status === "blocked" ? "detail.blocked" : target.state === "preview_active" ? "detail.preview" : target.state === "retained" || target.state === "delivered" || target.state === "cleanup_pending" ? "detail.saved" : "detail.ready";
|
|
@@ -10403,11 +10450,20 @@ function ReviewDetailsModal({ open, onClose, target, preflight }) {
|
|
|
10403
10450
|
"data-tone": recovery || conflict || preflight?.status === "blocked" ? "warning" : "neutral",
|
|
10404
10451
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: recovery || conflict ? "warning" : "list" }), note]
|
|
10405
10452
|
}) : null,
|
|
10453
|
+
conflict ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
10454
|
+
className: "dsh-wt-details-section",
|
|
10455
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("conflicting.files") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewDetailsList, {
|
|
10456
|
+
label: t("conflicting.files"),
|
|
10457
|
+
className: "dsh-wt-details-files",
|
|
10458
|
+
items: preflight.conflictingFiles.map((file) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "file" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: file })] }, file))
|
|
10459
|
+
}, `conflicts:${listKey}:${JSON.stringify(preflight.conflictingFiles)}`)]
|
|
10460
|
+
}) : null,
|
|
10406
10461
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
10407
10462
|
className: "dsh-wt-details-section",
|
|
10408
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("detail.files") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
10463
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("detail.files") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewDetailsList, {
|
|
10464
|
+
label: t("detail.files"),
|
|
10409
10465
|
className: "dsh-wt-details-files",
|
|
10410
|
-
|
|
10466
|
+
items: review.changedFiles.map((file) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
|
|
10411
10467
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "file" }),
|
|
10412
10468
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: file }),
|
|
10413
10469
|
conflict && preflight.conflictingFiles.includes(file) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -10416,7 +10472,7 @@ function ReviewDetailsModal({ open, onClose, target, preflight }) {
|
|
|
10416
10472
|
children: t("detail.conflict")
|
|
10417
10473
|
}) : null
|
|
10418
10474
|
] }, file))
|
|
10419
|
-
})]
|
|
10475
|
+
}, `files:${listKey}`)]
|
|
10420
10476
|
}),
|
|
10421
10477
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
10422
10478
|
className: "dsh-wt-details-section",
|
|
@@ -10426,16 +10482,17 @@ function ReviewDetailsModal({ open, onClose, target, preflight }) {
|
|
|
10426
10482
|
className: "dsh-wt-details-muted",
|
|
10427
10483
|
children: review.validationSummary
|
|
10428
10484
|
}) : null,
|
|
10429
|
-
review.tests.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
10485
|
+
review.tests.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewDetailsList, {
|
|
10486
|
+
label: t("detail.validation"),
|
|
10430
10487
|
className: "dsh-wt-details-tests",
|
|
10431
|
-
|
|
10488
|
+
items: review.tests.map((test, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: validationIcon(test.status) }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10432
10489
|
className: "dsh-wt-details-test-title",
|
|
10433
10490
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: test.command }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10434
10491
|
"data-validation": test.status,
|
|
10435
10492
|
children: validationText(test.status, t)
|
|
10436
10493
|
})]
|
|
10437
10494
|
}), test.summary ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: test.summary }) : null] })] }, index))
|
|
10438
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10495
|
+
}, `tests:${listKey}`) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10439
10496
|
className: "dsh-wt-details-muted",
|
|
10440
10497
|
children: t("detail.noTests")
|
|
10441
10498
|
})
|
|
@@ -10658,6 +10715,29 @@ function PreflightStatus({ snapshot, target, compact = false, onRefresh, onRecov
|
|
|
10658
10715
|
})]
|
|
10659
10716
|
});
|
|
10660
10717
|
const preflight = snapshot.preflight;
|
|
10718
|
+
if (preflight.status === "conflict") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10719
|
+
className: "dsh-wt-preflight dsh-wt-conflict",
|
|
10720
|
+
"data-preflight": "conflict",
|
|
10721
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10722
|
+
className: "dsh-wt-conflict-heading",
|
|
10723
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "warning" }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: statusLabel(preflight, t) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: t("read.only.check.local.unchanged") })] })]
|
|
10724
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10725
|
+
className: "dsh-wt-conflict-actions",
|
|
10726
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10727
|
+
type: "button",
|
|
10728
|
+
className: "dsh-wt-button",
|
|
10729
|
+
disabled: busy,
|
|
10730
|
+
onClick: onRefresh,
|
|
10731
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "refresh" }), t("check.again")]
|
|
10732
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10733
|
+
type: "button",
|
|
10734
|
+
className: "dsh-wt-button dsh-wt-primary",
|
|
10735
|
+
disabled: busy || !target?.capabilities.resumeRevision,
|
|
10736
|
+
onClick: () => onRecovery(preflight),
|
|
10737
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "warning" }), t("ask.agent.to.resolve.conflicts")]
|
|
10738
|
+
})]
|
|
10739
|
+
})]
|
|
10740
|
+
});
|
|
10661
10741
|
const blocked = preflight.status === "blocked";
|
|
10662
10742
|
const staleIsolated = blocked && preflight.reason === "stale_isolated" && preflight.reviewId !== null;
|
|
10663
10743
|
const holder = blocked && preflight.reason === "project_acceptance_busy" ? preflight.blocker ?? target?.reviewSlotHolder : void 0;
|
|
@@ -10682,11 +10762,6 @@ function PreflightStatus({ snapshot, target, compact = false, onRefresh, onRecov
|
|
|
10682
10762
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("changes") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: t("count.files", { count: preflight.changedFiles.length }) })] })
|
|
10683
10763
|
]
|
|
10684
10764
|
}) : null,
|
|
10685
|
-
!compact && preflight.status === "conflict" && preflight.conflictingFiles.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
10686
|
-
className: "dsh-wt-conflict-list",
|
|
10687
|
-
"aria-label": t("conflicting.files"),
|
|
10688
|
-
children: preflight.conflictingFiles.map((path) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", { children: path }) }, path))
|
|
10689
|
-
}) : null,
|
|
10690
10765
|
holder ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", { children: [
|
|
10691
10766
|
t("holding.task"),
|
|
10692
10767
|
holder.checkoutId.slice(0, 8),
|
|
@@ -10705,7 +10780,7 @@ function PreflightStatus({ snapshot, target, compact = false, onRefresh, onRecov
|
|
|
10705
10780
|
delivered: t("delivered")
|
|
10706
10781
|
}[holder.state]
|
|
10707
10782
|
] }) : null,
|
|
10708
|
-
|
|
10783
|
+
blocked ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10709
10784
|
className: "dsh-wt-recovery-actions",
|
|
10710
10785
|
children: [
|
|
10711
10786
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
@@ -10715,17 +10790,7 @@ function PreflightStatus({ snapshot, target, compact = false, onRefresh, onRecov
|
|
|
10715
10790
|
onClick: onRefresh,
|
|
10716
10791
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "refresh" }), t("check.again")]
|
|
10717
10792
|
}),
|
|
10718
|
-
|
|
10719
|
-
type: "button",
|
|
10720
|
-
className: "dsh-wt-inline-action",
|
|
10721
|
-
disabled: busy || !target?.capabilities.resumeRevision,
|
|
10722
|
-
onClick: () => onRecovery(preflight),
|
|
10723
|
-
children: [
|
|
10724
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "warning" }),
|
|
10725
|
-
t("ask.agent.to.resolve.conflicts"),
|
|
10726
|
-
" "
|
|
10727
|
-
]
|
|
10728
|
-
}) : staleIsolated ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10793
|
+
staleIsolated ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10729
10794
|
type: "button",
|
|
10730
10795
|
className: "dsh-wt-inline-action",
|
|
10731
10796
|
disabled: busy,
|
|
@@ -11673,7 +11738,7 @@ function ReviewActions({ review, adapter, services, identity, target, disabled,
|
|
|
11673
11738
|
const checkpoint = async () => {
|
|
11674
11739
|
const value = checkpointMessage.trim();
|
|
11675
11740
|
const requestId = checkpointRequestId.current;
|
|
11676
|
-
if (!value ||
|
|
11741
|
+
if (!isValidCommitMessage(value) || !requestId || !begin("checkpoint") || !adapter || !identity || !target?.checkpointGeneration) return;
|
|
11677
11742
|
const expectedCount = target.checkpoints?.length ?? 0;
|
|
11678
11743
|
const outcome = await adapter.checkpoint({
|
|
11679
11744
|
...identity,
|
|
@@ -11787,7 +11852,7 @@ function ReviewActions({ review, adapter, services, identity, target, disabled,
|
|
|
11787
11852
|
const submitCommit = async () => {
|
|
11788
11853
|
const value = commitMessage.trim();
|
|
11789
11854
|
const mode = commitMode;
|
|
11790
|
-
if (!mode || !value ||
|
|
11855
|
+
if (!mode || !isValidCommitMessage(value) || !begin(mode) || !adapter || !identity) return;
|
|
11791
11856
|
const selectedRetention = retainEnvironment ? retention : "cleanup";
|
|
11792
11857
|
const request = {
|
|
11793
11858
|
...identity,
|
|
@@ -12124,7 +12189,7 @@ function ReviewActions({ review, adapter, services, identity, target, disabled,
|
|
|
12124
12189
|
},
|
|
12125
12190
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "refresh" }), submitting === "retry_cleanup" ? t("cleaning.up") : t("retry.environment.cleanup")]
|
|
12126
12191
|
}) : null;
|
|
12127
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
12192
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
12128
12193
|
className: "dsh-wt-review-actions",
|
|
12129
12194
|
"aria-label": t("review.actions"),
|
|
12130
12195
|
children: [
|
|
@@ -12132,123 +12197,126 @@ function ReviewActions({ review, adapter, services, identity, target, disabled,
|
|
|
12132
12197
|
className: "dsh-wt-status",
|
|
12133
12198
|
children: unavailableMessage
|
|
12134
12199
|
}) : null,
|
|
12135
|
-
|
|
12136
|
-
className: "dsh-wt-
|
|
12137
|
-
children:
|
|
12138
|
-
|
|
12139
|
-
|
|
12140
|
-
|
|
12141
|
-
|
|
12142
|
-
|
|
12143
|
-
|
|
12144
|
-
className: "dsh-wt-more-
|
|
12145
|
-
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
|
|
12162
|
-
|
|
12200
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12201
|
+
className: renderStatus ? "dsh-wt-review-action-head" : void 0,
|
|
12202
|
+
children: [renderStatus?.(submitting), terminal ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
12203
|
+
className: "dsh-wt-status",
|
|
12204
|
+
children: target.state === "retained" ? t("this.iteration.was.committed.the.environment.is.temporarily", { p0: target.commitOid ? ` · ${target.commitOid.slice(0, 8)}` : "" }) : t("this.iteration.was.delivered", { p0: target.commitOid ? ` · ${target.commitOid.slice(0, 8)}` : "" })
|
|
12205
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12206
|
+
className: "dsh-wt-actions",
|
|
12207
|
+
children: [ready && preflightSnapshot.status === "success" && preflightSnapshot.preflight.status === "conflict" ? null : primary, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
12208
|
+
ref: moreMenuRef,
|
|
12209
|
+
className: "dsh-wt-more-menu",
|
|
12210
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", {
|
|
12211
|
+
className: "dsh-wt-more-trigger",
|
|
12212
|
+
"aria-label": t("more.delivery.actions"),
|
|
12213
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "more" })
|
|
12214
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12215
|
+
className: "dsh-wt-more-content",
|
|
12216
|
+
role: "menu",
|
|
12217
|
+
children: [
|
|
12218
|
+
focusReview && !renderStatus ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12219
|
+
type: "button",
|
|
12220
|
+
role: "menuitem",
|
|
12221
|
+
className: "dsh-wt-more-item",
|
|
12222
|
+
onClick: () => {
|
|
12223
|
+
focusReview();
|
|
12224
|
+
closeMoreMenu();
|
|
12225
|
+
},
|
|
12226
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "list" }), t("view.review")]
|
|
12227
|
+
}) : null,
|
|
12228
|
+
ready ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
12229
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12230
|
+
type: "button",
|
|
12231
|
+
role: "menuitem",
|
|
12232
|
+
className: "dsh-wt-more-item",
|
|
12233
|
+
disabled: allDisabled || !target.capabilities.checkpoint || !target.checkpointGeneration,
|
|
12234
|
+
onClick: () => {
|
|
12235
|
+
openCheckpoint();
|
|
12236
|
+
closeMoreMenu();
|
|
12237
|
+
},
|
|
12238
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "save" }), t("save.stage.and.continue")]
|
|
12239
|
+
}),
|
|
12240
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12241
|
+
type: "button",
|
|
12242
|
+
role: "menuitem",
|
|
12243
|
+
className: "dsh-wt-more-item",
|
|
12244
|
+
disabled: allDisabled || !target.capabilities.resumeRevision,
|
|
12245
|
+
onClick: () => {
|
|
12246
|
+
resumeRevision();
|
|
12247
|
+
closeMoreMenu();
|
|
12248
|
+
},
|
|
12249
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "edit" }), submitting === "resume_revision" ? t("recovering") : t("continue.editing")]
|
|
12250
|
+
}),
|
|
12251
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12252
|
+
type: "button",
|
|
12253
|
+
role: "menuitem",
|
|
12254
|
+
className: "dsh-wt-more-item",
|
|
12255
|
+
disabled: allDisabled || !target.capabilities.finalize || !safeReadyPreflight,
|
|
12256
|
+
onClick: () => {
|
|
12257
|
+
setCommitMode("finish");
|
|
12258
|
+
closeMoreMenu();
|
|
12259
|
+
},
|
|
12260
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "confirm" }), t("skip.preview.and.save")]
|
|
12261
|
+
})
|
|
12262
|
+
] }) : null,
|
|
12263
|
+
previewActive && target.capabilities.checkpoint && target.checkpointGeneration ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12163
12264
|
type: "button",
|
|
12164
12265
|
role: "menuitem",
|
|
12165
12266
|
className: "dsh-wt-more-item",
|
|
12166
|
-
disabled: allDisabled
|
|
12267
|
+
disabled: allDisabled,
|
|
12167
12268
|
onClick: () => {
|
|
12168
12269
|
openCheckpoint();
|
|
12169
12270
|
closeMoreMenu();
|
|
12170
12271
|
},
|
|
12171
12272
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "save" }), t("save.stage.and.continue")]
|
|
12172
|
-
}),
|
|
12173
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12273
|
+
}) : null,
|
|
12274
|
+
previewActive ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12174
12275
|
type: "button",
|
|
12175
12276
|
role: "menuitem",
|
|
12176
12277
|
className: "dsh-wt-more-item",
|
|
12177
|
-
disabled: allDisabled || !target.capabilities.
|
|
12278
|
+
disabled: allDisabled || !target.capabilities.rollbackPreview,
|
|
12178
12279
|
onClick: () => {
|
|
12179
|
-
|
|
12280
|
+
rollbackPreview(true);
|
|
12180
12281
|
closeMoreMenu();
|
|
12181
12282
|
},
|
|
12182
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "edit" }),
|
|
12183
|
-
}),
|
|
12184
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12283
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "edit" }), t("continue.editing")]
|
|
12284
|
+
}) : null,
|
|
12285
|
+
previewActive || rollbackRecoverySafe ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12185
12286
|
type: "button",
|
|
12186
12287
|
role: "menuitem",
|
|
12187
12288
|
className: "dsh-wt-more-item",
|
|
12188
|
-
disabled: allDisabled || !target.capabilities.
|
|
12289
|
+
disabled: allDisabled || !target.capabilities.rollbackPreview,
|
|
12189
12290
|
onClick: () => {
|
|
12190
|
-
|
|
12291
|
+
rollbackPreview();
|
|
12191
12292
|
closeMoreMenu();
|
|
12192
12293
|
},
|
|
12193
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "
|
|
12194
|
-
})
|
|
12195
|
-
|
|
12196
|
-
|
|
12197
|
-
|
|
12198
|
-
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
|
|
12202
|
-
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
|
|
12209
|
-
|
|
12210
|
-
|
|
12211
|
-
|
|
12212
|
-
|
|
12213
|
-
|
|
12214
|
-
|
|
12215
|
-
|
|
12216
|
-
|
|
12217
|
-
|
|
12218
|
-
|
|
12219
|
-
type: "button",
|
|
12220
|
-
role: "menuitem",
|
|
12221
|
-
className: "dsh-wt-more-item",
|
|
12222
|
-
disabled: allDisabled || !target.capabilities.rollbackPreview,
|
|
12223
|
-
onClick: () => {
|
|
12224
|
-
rollbackPreview();
|
|
12225
|
-
closeMoreMenu();
|
|
12226
|
-
},
|
|
12227
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "rollback" }), previewActive ? t("roll.back.this.preview") : t("retry.rollback")]
|
|
12228
|
-
}) : null,
|
|
12229
|
-
finalizeRecoverySafe ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12230
|
-
type: "button",
|
|
12231
|
-
role: "menuitem",
|
|
12232
|
-
className: "dsh-wt-more-item",
|
|
12233
|
-
disabled: allDisabled || !target.capabilities.finalizePreview,
|
|
12234
|
-
onClick: () => {
|
|
12235
|
-
setCommitMode("finalize_preview");
|
|
12236
|
-
closeMoreMenu();
|
|
12237
|
-
},
|
|
12238
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "confirm" }), t("save.changes")]
|
|
12239
|
-
}) : null,
|
|
12240
|
-
canDiscard ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12241
|
-
type: "button",
|
|
12242
|
-
role: "menuitem",
|
|
12243
|
-
className: "dsh-wt-more-item dsh-wt-danger-text",
|
|
12244
|
-
disabled: allDisabled,
|
|
12245
|
-
onClick: () => {
|
|
12246
|
-
setDiscardOpen(true);
|
|
12247
|
-
closeMoreMenu();
|
|
12248
|
-
},
|
|
12249
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "discard" }), t("discard.task")]
|
|
12250
|
-
}) : null
|
|
12251
|
-
]
|
|
12294
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "rollback" }), previewActive ? t("roll.back.this.preview") : t("retry.rollback")]
|
|
12295
|
+
}) : null,
|
|
12296
|
+
finalizeRecoverySafe ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12297
|
+
type: "button",
|
|
12298
|
+
role: "menuitem",
|
|
12299
|
+
className: "dsh-wt-more-item",
|
|
12300
|
+
disabled: allDisabled || !target.capabilities.finalizePreview,
|
|
12301
|
+
onClick: () => {
|
|
12302
|
+
setCommitMode("finalize_preview");
|
|
12303
|
+
closeMoreMenu();
|
|
12304
|
+
},
|
|
12305
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "confirm" }), t("save.changes")]
|
|
12306
|
+
}) : null,
|
|
12307
|
+
canDiscard ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12308
|
+
type: "button",
|
|
12309
|
+
role: "menuitem",
|
|
12310
|
+
className: "dsh-wt-more-item dsh-wt-danger-text",
|
|
12311
|
+
disabled: allDisabled,
|
|
12312
|
+
onClick: () => {
|
|
12313
|
+
setDiscardOpen(true);
|
|
12314
|
+
closeMoreMenu();
|
|
12315
|
+
},
|
|
12316
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "discard" }), t("discard.task")]
|
|
12317
|
+
}) : null
|
|
12318
|
+
]
|
|
12319
|
+
})]
|
|
12252
12320
|
})]
|
|
12253
12321
|
})]
|
|
12254
12322
|
}),
|
|
@@ -12269,7 +12337,7 @@ function ReviewActions({ review, adapter, services, identity, target, disabled,
|
|
|
12269
12337
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12270
12338
|
type: "button",
|
|
12271
12339
|
className: "dsh-wt-button dsh-wt-primary",
|
|
12272
|
-
disabled: submitting !== null || !
|
|
12340
|
+
disabled: submitting !== null || !isValidCommitMessage(checkpointMessage),
|
|
12273
12341
|
onClick: () => {
|
|
12274
12342
|
checkpoint();
|
|
12275
12343
|
},
|
|
@@ -12291,13 +12359,12 @@ function ReviewActions({ review, adapter, services, identity, target, disabled,
|
|
|
12291
12359
|
id: `${formId}-checkpoint-message`,
|
|
12292
12360
|
"aria-label": t("checkpoint.commit.message"),
|
|
12293
12361
|
rows: 6,
|
|
12294
|
-
maxLength: 500,
|
|
12295
12362
|
value: checkpointMessage,
|
|
12296
12363
|
onChange: (event) => setCheckpointMessage(event.target.value)
|
|
12297
12364
|
}),
|
|
12298
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
12365
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12299
12366
|
className: "dsh-wt-character-count",
|
|
12300
|
-
children:
|
|
12367
|
+
children: checkpointMessage.length
|
|
12301
12368
|
})
|
|
12302
12369
|
]
|
|
12303
12370
|
})
|
|
@@ -12319,7 +12386,7 @@ function ReviewActions({ review, adapter, services, identity, target, disabled,
|
|
|
12319
12386
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12320
12387
|
type: "button",
|
|
12321
12388
|
className: "dsh-wt-button dsh-wt-primary",
|
|
12322
|
-
disabled: submitting !== null || !
|
|
12389
|
+
disabled: submitting !== null || !isValidCommitMessage(commitMessage),
|
|
12323
12390
|
onClick: () => {
|
|
12324
12391
|
submitCommit();
|
|
12325
12392
|
},
|
|
@@ -12337,13 +12404,12 @@ function ReviewActions({ review, adapter, services, identity, target, disabled,
|
|
|
12337
12404
|
id: `${formId}-message`,
|
|
12338
12405
|
"aria-label": t("commit.message"),
|
|
12339
12406
|
rows: 6,
|
|
12340
|
-
maxLength: 500,
|
|
12341
12407
|
value: commitMessage,
|
|
12342
12408
|
onChange: (event) => setCommitMessage(event.target.value)
|
|
12343
12409
|
}),
|
|
12344
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
12410
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12345
12411
|
className: "dsh-wt-character-count",
|
|
12346
|
-
children:
|
|
12412
|
+
children: commitMessage.length
|
|
12347
12413
|
}),
|
|
12348
12414
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
12349
12415
|
className: "dsh-wt-retention-check",
|
|
@@ -12559,7 +12625,7 @@ function ReviewActions({ review, adapter, services, identity, target, disabled,
|
|
|
12559
12625
|
}), " "]
|
|
12560
12626
|
}) : null
|
|
12561
12627
|
]
|
|
12562
|
-
})
|
|
12628
|
+
}) });
|
|
12563
12629
|
}
|
|
12564
12630
|
|
|
12565
12631
|
//#endregion
|
|
@@ -12699,12 +12765,6 @@ function WorktreeReviewStatus({ session, adapter, services }) {
|
|
|
12699
12765
|
className: "dsh-wt-error",
|
|
12700
12766
|
children: error
|
|
12701
12767
|
}) : null,
|
|
12702
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12703
|
-
type: "button",
|
|
12704
|
-
className: "dsh-wt-details-trigger",
|
|
12705
|
-
onClick: () => setDetailsOpen(true),
|
|
12706
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "list" }), t("detail.view")]
|
|
12707
|
-
}),
|
|
12708
12768
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewDetailsModal, {
|
|
12709
12769
|
open: detailsOpen,
|
|
12710
12770
|
onClose: () => setDetailsOpen(false),
|
|
@@ -12720,7 +12780,7 @@ function WorktreeReviewStatus({ session, adapter, services }) {
|
|
|
12720
12780
|
disabled: false,
|
|
12721
12781
|
unavailableMessage: t("live.worktree.console.is.disconnected"),
|
|
12722
12782
|
focusReview: () => setDetailsOpen(true),
|
|
12723
|
-
renderStatus: (operation) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
12783
|
+
renderStatus: (operation) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
12724
12784
|
className: "dsh-wt-review-dock-copy",
|
|
12725
12785
|
role: "status",
|
|
12726
12786
|
"aria-live": "polite",
|
|
@@ -12741,7 +12801,12 @@ function WorktreeReviewStatus({ session, adapter, services }) {
|
|
|
12741
12801
|
}),
|
|
12742
12802
|
target.state === "preview_detached" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: detail }) : null
|
|
12743
12803
|
]
|
|
12744
|
-
}),
|
|
12804
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12805
|
+
type: "button",
|
|
12806
|
+
className: "dsh-wt-details-trigger",
|
|
12807
|
+
onClick: () => setDetailsOpen(true),
|
|
12808
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReviewIcon, { name: "list" }), t("detail.view")]
|
|
12809
|
+
})] }),
|
|
12745
12810
|
isActive: () => mounted.current && currentSessionId.current === sessionId && sessionGeneration.current === actionGeneration,
|
|
12746
12811
|
onStale: () => {
|
|
12747
12812
|
refresh();
|
|
@@ -13018,10 +13083,10 @@ const official$2 = ((require$1) => {
|
|
|
13018
13083
|
var exports$1 = module$1.exports;
|
|
13019
13084
|
Object.defineProperty(exports$1, Symbol.toStringTag, { value: "Module" });
|
|
13020
13085
|
let _deepseek_ai_dsh_client_store = require$1("@deepseek-ai/dsh-client-store");
|
|
13086
|
+
let _deepseek_ai_dsh_client_ui_primitives = require$1("@deepseek-ai/dsh-client-ui-primitives");
|
|
13021
13087
|
let _deepseek_ai_cordis = require$1("@deepseek-ai/cordis");
|
|
13022
13088
|
let react_jsx_runtime$1 = require$1("react/jsx-runtime");
|
|
13023
13089
|
let react$1 = require$1("react");
|
|
13024
|
-
let _deepseek_ai_dsh_client_ui_primitives = require$1("@deepseek-ai/dsh-client-ui-primitives");
|
|
13025
13090
|
/**
|
|
13026
13091
|
* Bind the row's render occurrence into the entries' `useMenuOpenState` hook:
|
|
13027
13092
|
* the owner supplies its open-state pair as the occurrence's `hookContext`,
|
|
@@ -13040,10 +13105,8 @@ const official$2 = ((require$1) => {
|
|
|
13040
13105
|
searchRequest: 0,
|
|
13041
13106
|
addRequested: false,
|
|
13042
13107
|
directoryBusy: false,
|
|
13043
|
-
renameTarget: null
|
|
13044
|
-
forkError: null
|
|
13108
|
+
renameTarget: null
|
|
13045
13109
|
});
|
|
13046
|
-
let forkErrorSeq = 0;
|
|
13047
13110
|
return {
|
|
13048
13111
|
state,
|
|
13049
13112
|
search: () => {
|
|
@@ -13084,22 +13147,6 @@ const official$2 = ((require$1) => {
|
|
|
13084
13147
|
...state.getSnapshot(),
|
|
13085
13148
|
renameTarget: null
|
|
13086
13149
|
});
|
|
13087
|
-
},
|
|
13088
|
-
forkFailed: (reason) => {
|
|
13089
|
-
forkErrorSeq += 1;
|
|
13090
|
-
state.set({
|
|
13091
|
-
...state.getSnapshot(),
|
|
13092
|
-
forkError: {
|
|
13093
|
-
reason,
|
|
13094
|
-
seq: forkErrorSeq
|
|
13095
|
-
}
|
|
13096
|
-
});
|
|
13097
|
-
},
|
|
13098
|
-
dismissForkError: () => {
|
|
13099
|
-
state.set({
|
|
13100
|
-
...state.getSnapshot(),
|
|
13101
|
-
forkError: null
|
|
13102
|
-
});
|
|
13103
13150
|
}
|
|
13104
13151
|
};
|
|
13105
13152
|
}
|
|
@@ -13110,8 +13157,9 @@ const official$2 = ((require$1) => {
|
|
|
13110
13157
|
* @param navigation - session creation and forking from the pointer controls' navigation service.
|
|
13111
13158
|
* @param controls - browser-owned opening requests.
|
|
13112
13159
|
* @param archiveSession - shared archive action, including running-work confirmation and notices.
|
|
13160
|
+
* @param reportForkFailure - publish a classified failure through the frame-wide notice channel.
|
|
13113
13161
|
*/
|
|
13114
|
-
function installWorkspaceShortcuts(ctx, navigation, controls, archiveSession) {
|
|
13162
|
+
function installWorkspaceShortcuts(ctx, navigation, controls, archiveSession, reportForkFailure) {
|
|
13115
13163
|
const t = ctx.locale.bind("workspace");
|
|
13116
13164
|
const current = () => Object.values(ctx.sessions.list.getSnapshot().byId).find((row) => (row.retainedBy.mainView ?? 0) > 0);
|
|
13117
13165
|
const addReason = () => ctx.slots.entries("sidebar.workspaces.directoryFlow").length === 0 ? t("shortcut.noPicker") : controls.state.getSnapshot().directoryBusy ? t("shortcut.directoryBusy") : null;
|
|
@@ -13194,7 +13242,7 @@ const official$2 = ((require$1) => {
|
|
|
13194
13242
|
run: () => {
|
|
13195
13243
|
navigation.forkSession(target.id).catch((error) => {
|
|
13196
13244
|
const unavailable = error instanceof Error && error.name === "SessionForkError" && error.rpcError.code === "session/fork-unavailable";
|
|
13197
|
-
|
|
13245
|
+
reportForkFailure(unavailable ? "unavailable" : "failed");
|
|
13198
13246
|
if (!unavailable) console.warn("session fork rejected:", error);
|
|
13199
13247
|
});
|
|
13200
13248
|
}
|
|
@@ -13214,137 +13262,757 @@ const official$2 = ((require$1) => {
|
|
|
13214
13262
|
});
|
|
13215
13263
|
}
|
|
13216
13264
|
/**
|
|
13217
|
-
*
|
|
13218
|
-
*
|
|
13219
|
-
*
|
|
13220
|
-
*
|
|
13221
|
-
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
throw new Error(`unreachable variant${context ? ` in ${context}` : ""}: ${rendered}`);
|
|
13225
|
-
}
|
|
13226
|
-
/** Whether a path uses a Windows drive or UNC prefix. */
|
|
13227
|
-
function isWindowsStylePath(value) {
|
|
13228
|
-
return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
|
|
13229
|
-
}
|
|
13230
|
-
/**
|
|
13231
|
-
* Abbreviate a POSIX home directory for display.
|
|
13232
|
-
* @param path - Absolute or already-short display path.
|
|
13233
|
-
* @param home - Host account home; absent skips abbreviation.
|
|
13234
|
-
* @returns `~` or `~/…` for the POSIX home and its descendants, otherwise `path`.
|
|
13235
|
-
*/
|
|
13236
|
-
function abbreviateHomePath(path, home) {
|
|
13237
|
-
if (home === void 0 || home === "") return path;
|
|
13238
|
-
if (isWindowsStylePath(path) || isWindowsStylePath(home)) return path;
|
|
13239
|
-
const root = home.replace(/\/+$/, "");
|
|
13240
|
-
if (root === "" || root === "/") return path;
|
|
13241
|
-
if (path.replace(/\/+$/, "") === root) return "~";
|
|
13242
|
-
if (path.startsWith(`${root}/`)) return `~${path.slice(root.length)}`;
|
|
13243
|
-
return path;
|
|
13244
|
-
}
|
|
13245
|
-
/**
|
|
13246
|
-
* Read the final non-empty segment of a Workspace path for display.
|
|
13247
|
-
* Workspace-label surfaces use this helper instead of deriving another basename.
|
|
13248
|
-
* @param path - Workspace directory path using POSIX or Windows separators.
|
|
13249
|
-
* @returns the final segment, or an empty string for a separator-only path.
|
|
13250
|
-
*/
|
|
13251
|
-
function workspaceTitleOf(path) {
|
|
13252
|
-
const trimmed = path.replace(/[/\\]+$/, "");
|
|
13253
|
-
const separator = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
13254
|
-
return trimmed.slice(separator + 1);
|
|
13255
|
-
}
|
|
13256
|
-
/**
|
|
13257
|
-
* Resolve the Workspace browser group that owns one Session.
|
|
13258
|
-
* @param workspaces - authoritative Workspace membership.
|
|
13259
|
-
* @param sessionId - Session whose browser group is required.
|
|
13260
|
-
* @returns owning Workspace id, or {@link UNGROUPED_KEY} when no Workspace accounts for it.
|
|
13261
|
-
*/
|
|
13262
|
-
function owningGroupKey(workspaces, sessionId) {
|
|
13263
|
-
return workspaces.find((workspace) => workspace.sessionIds.includes(sessionId))?.workspaceId ?? "";
|
|
13264
|
-
}
|
|
13265
|
-
function mainSessionId(list) {
|
|
13266
|
-
return Object.values(list.byId).find((session) => (session.retainedBy.mainView ?? 0) > 0)?.id;
|
|
13267
|
-
}
|
|
13268
|
-
/**
|
|
13269
|
-
* Directory display label: basename of the path (both separators accepted).
|
|
13270
|
-
* Ungrouped-bucket fallback for surfaces without a workspace title.
|
|
13271
|
-
* @param cwd - directory path, or undefined for the ungrouped bucket.
|
|
13272
|
-
* @returns basename, the raw cwd when it has no basename, or an empty ungrouped marker.
|
|
13265
|
+
* Lazily scanned view of one JSON object's top-level fields, built from text
|
|
13266
|
+
* that may still be streaming or from an already parsed object. Nothing is
|
|
13267
|
+
* scanned until a reader asks; the view remembers every question it answered
|
|
13268
|
+
* and reports changed answers when the owner refreshes for publication.
|
|
13269
|
+
* Used for model tool-call arguments: a row reads the fields it
|
|
13270
|
+
* cares about at whatever granularity it displays, at every stage of the call.
|
|
13271
|
+
* @module @deepseek-ai/dsh-util-values/src/partial-json
|
|
13273
13272
|
*/
|
|
13274
|
-
|
|
13275
|
-
|
|
13276
|
-
|
|
13277
|
-
|
|
13273
|
+
const SIMPLE_ESCAPES = {
|
|
13274
|
+
"\"": "\"",
|
|
13275
|
+
"\\": "\\",
|
|
13276
|
+
"/": "/",
|
|
13277
|
+
b: "\b",
|
|
13278
|
+
f: "\f",
|
|
13279
|
+
n: "\n",
|
|
13280
|
+
r: "\r",
|
|
13281
|
+
t: " "
|
|
13282
|
+
};
|
|
13283
|
+
const CONTENT_ESCAPE = /[\\\u0000-\u001f]/u;
|
|
13284
|
+
function isWhitespace(c) {
|
|
13285
|
+
return c === " " || c === "\n" || c === "\r" || c === " ";
|
|
13278
13286
|
}
|
|
13279
|
-
|
|
13280
|
-
|
|
13281
|
-
* @param sessionIds - authoritative account membership.
|
|
13282
|
-
* @param summaries - current Session summaries; members without a summary are omitted until it arrives.
|
|
13283
|
-
* @returns known members newest first, with Session identity as the deterministic tie-break.
|
|
13284
|
-
*/
|
|
13285
|
-
function orderByRecency(sessionIds, summaries) {
|
|
13286
|
-
return sessionIds.flatMap((id) => {
|
|
13287
|
-
const summary = summaries[id];
|
|
13288
|
-
if (summary === void 0) return [];
|
|
13289
|
-
return [{
|
|
13290
|
-
id,
|
|
13291
|
-
rank: summary.updatedAt
|
|
13292
|
-
}];
|
|
13293
|
-
}).sort((a, b) => {
|
|
13294
|
-
if (a.rank !== b.rank) return b.rank - a.rank;
|
|
13295
|
-
return a.id < b.id ? -1 : 1;
|
|
13296
|
-
}).map((member) => member.id);
|
|
13287
|
+
function isHex(c) {
|
|
13288
|
+
return c >= "0" && c <= "9" || c >= "a" && c <= "f" || c >= "A" && c <= "F";
|
|
13297
13289
|
}
|
|
13298
|
-
|
|
13299
|
-
|
|
13300
|
-
|
|
13301
|
-
|
|
13302
|
-
|
|
13303
|
-
|
|
13304
|
-
|
|
13305
|
-
|
|
13306
|
-
|
|
13307
|
-
|
|
13308
|
-
|
|
13309
|
-
|
|
13310
|
-
|
|
13311
|
-
for (const key of savedOrder ?? []) {
|
|
13312
|
-
const id = members.get(key);
|
|
13313
|
-
if (id === void 0 || included.has(key)) continue;
|
|
13314
|
-
ordered.push(id);
|
|
13315
|
-
included.add(key);
|
|
13290
|
+
(class PartialArguments {
|
|
13291
|
+
/** The view of a call with no arguments available. */
|
|
13292
|
+
static EMPTY = PartialArguments.fromObject({});
|
|
13293
|
+
/**
|
|
13294
|
+
* View finished argument text without scanning it until a reader asks.
|
|
13295
|
+
* @param text - the complete argument JSON text.
|
|
13296
|
+
* @returns a sealed view.
|
|
13297
|
+
*/
|
|
13298
|
+
static fromText(text) {
|
|
13299
|
+
const view = new PartialArguments();
|
|
13300
|
+
view.append(text);
|
|
13301
|
+
view.sealed = true;
|
|
13302
|
+
return view;
|
|
13316
13303
|
}
|
|
13317
|
-
|
|
13318
|
-
|
|
13319
|
-
|
|
13320
|
-
|
|
13321
|
-
|
|
13322
|
-
|
|
13323
|
-
|
|
13304
|
+
/**
|
|
13305
|
+
* View an already parsed argument payload, such as a PTC dispatch object.
|
|
13306
|
+
* @param value - the parsed argument value.
|
|
13307
|
+
* @returns a sealed view; a non-object payload has no fields.
|
|
13308
|
+
*/
|
|
13309
|
+
static fromObject(value) {
|
|
13310
|
+
const view = new PartialArguments();
|
|
13311
|
+
view.object = typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
|
|
13312
|
+
view.sealed = true;
|
|
13313
|
+
return view;
|
|
13324
13314
|
}
|
|
13325
|
-
|
|
13326
|
-
|
|
13327
|
-
|
|
13328
|
-
|
|
13329
|
-
|
|
13330
|
-
|
|
13331
|
-
|
|
13332
|
-
|
|
13333
|
-
|
|
13334
|
-
|
|
13335
|
-
|
|
13336
|
-
|
|
13337
|
-
|
|
13338
|
-
|
|
13339
|
-
|
|
13340
|
-
|
|
13341
|
-
|
|
13342
|
-
|
|
13343
|
-
|
|
13344
|
-
|
|
13345
|
-
|
|
13346
|
-
|
|
13347
|
-
|
|
13315
|
+
/**
|
|
13316
|
+
* The source: text so far or a parsed object, plus whether it can still grow.
|
|
13317
|
+
* These are the only enumerable fields, so two views over the same source
|
|
13318
|
+
* compare equal structurally however far each has been read.
|
|
13319
|
+
*/
|
|
13320
|
+
chunks = [];
|
|
13321
|
+
object;
|
|
13322
|
+
sealed = false;
|
|
13323
|
+
#ends = [];
|
|
13324
|
+
#size = 0;
|
|
13325
|
+
#consumed = 0;
|
|
13326
|
+
#mode = "root";
|
|
13327
|
+
#escape = false;
|
|
13328
|
+
#keyStart = 0;
|
|
13329
|
+
#keyEscaped = false;
|
|
13330
|
+
#key = "";
|
|
13331
|
+
#current = null;
|
|
13332
|
+
#nestedEnds = [];
|
|
13333
|
+
#nestedInString = false;
|
|
13334
|
+
#invalidAt;
|
|
13335
|
+
#invalidValue = false;
|
|
13336
|
+
#entries = /* @__PURE__ */ new Map();
|
|
13337
|
+
#order = [];
|
|
13338
|
+
#reads = /* @__PURE__ */ new Map();
|
|
13339
|
+
/** Whether this view rejects further appends; does not scan text or register reads. */
|
|
13340
|
+
get isSealed() {
|
|
13341
|
+
return this.sealed;
|
|
13342
|
+
}
|
|
13343
|
+
/** Whether indexing or a content read found invalid JSON; unread value contents are not validated. */
|
|
13344
|
+
get invalid() {
|
|
13345
|
+
this.scan();
|
|
13346
|
+
return this.#mode === "invalid" || this.#invalidValue;
|
|
13347
|
+
}
|
|
13348
|
+
/**
|
|
13349
|
+
* Retain streamed argument text without scanning or comparing observed answers.
|
|
13350
|
+
* @param fragment - the text following every fragment appended before.
|
|
13351
|
+
*/
|
|
13352
|
+
append(fragment) {
|
|
13353
|
+
if (this.sealed) throw new Error("PartialArguments: cannot append to a sealed view");
|
|
13354
|
+
if (fragment.length === 0) return;
|
|
13355
|
+
this.chunks.push(fragment);
|
|
13356
|
+
this.#size += fragment.length;
|
|
13357
|
+
this.#ends.push(this.#size);
|
|
13358
|
+
}
|
|
13359
|
+
/**
|
|
13360
|
+
* Reconcile a streamed prefix with authoritative complete text without joining the fragments.
|
|
13361
|
+
* @param text - the final argument text, which replaces missing or conflicting deltas.
|
|
13362
|
+
* @returns this view sealed with its caches retained when every character matches; otherwise a new sealed view.
|
|
13363
|
+
*/
|
|
13364
|
+
settle(text) {
|
|
13365
|
+
if (this.object !== void 0 || text.length !== this.#size) return PartialArguments.fromText(text);
|
|
13366
|
+
let offset = 0;
|
|
13367
|
+
for (const chunk of this.chunks) {
|
|
13368
|
+
if (!text.startsWith(chunk, offset)) return PartialArguments.fromText(text);
|
|
13369
|
+
offset += chunk.length;
|
|
13370
|
+
}
|
|
13371
|
+
this.chunks = text.length === 0 ? [] : [text];
|
|
13372
|
+
this.#ends = text.length === 0 ? [] : [text.length];
|
|
13373
|
+
this.sealed = true;
|
|
13374
|
+
return this;
|
|
13375
|
+
}
|
|
13376
|
+
/**
|
|
13377
|
+
* Compare observed answers and advance their publication baseline. Unread views remain unscanned.
|
|
13378
|
+
* @returns whether any observed answer changed since its first read or the preceding refresh.
|
|
13379
|
+
*/
|
|
13380
|
+
refresh() {
|
|
13381
|
+
if (this.#reads.size === 0) return false;
|
|
13382
|
+
this.scan();
|
|
13383
|
+
let changed = false;
|
|
13384
|
+
let completions = false;
|
|
13385
|
+
for (const read of this.#reads.values()) {
|
|
13386
|
+
if (read.completion) {
|
|
13387
|
+
completions = true;
|
|
13388
|
+
continue;
|
|
13389
|
+
}
|
|
13390
|
+
changed = this.refreshRead(read) || changed;
|
|
13391
|
+
}
|
|
13392
|
+
if (completions) {
|
|
13393
|
+
for (const read of this.#reads.values()) if (read.completion) changed = this.refreshRead(read) || changed;
|
|
13394
|
+
}
|
|
13395
|
+
if (this.sealed) this.#reads.clear();
|
|
13396
|
+
return changed;
|
|
13397
|
+
}
|
|
13398
|
+
refreshRead(read) {
|
|
13399
|
+
const now = read.answer();
|
|
13400
|
+
if (Object.is(now, read.last)) return false;
|
|
13401
|
+
read.last = now;
|
|
13402
|
+
return true;
|
|
13403
|
+
}
|
|
13404
|
+
/**
|
|
13405
|
+
* Check whether no further fields can arrive.
|
|
13406
|
+
* @returns whether the outer object closed, indexing failed, or the view is sealed; unread values are not validated.
|
|
13407
|
+
*/
|
|
13408
|
+
closed() {
|
|
13409
|
+
return this.remember("closed", "", () => this.closedNow());
|
|
13410
|
+
}
|
|
13411
|
+
/**
|
|
13412
|
+
* List discovered fields in first-appearance order.
|
|
13413
|
+
* @returns top-level keys seen so far, in first-appearance order.
|
|
13414
|
+
*/
|
|
13415
|
+
keys() {
|
|
13416
|
+
return this.remember("keys", "", () => this.keysNow(), (keys) => keys.length);
|
|
13417
|
+
}
|
|
13418
|
+
/**
|
|
13419
|
+
* Check whether a top-level field has appeared.
|
|
13420
|
+
* @param key - argument name.
|
|
13421
|
+
* @returns whether the field has appeared (a string opened or another value began).
|
|
13422
|
+
*/
|
|
13423
|
+
has(key) {
|
|
13424
|
+
return this.remember("has", key, () => this.hasNow(key));
|
|
13425
|
+
}
|
|
13426
|
+
/**
|
|
13427
|
+
* Check whether a field's closing delimiter has arrived, without validating its contents.
|
|
13428
|
+
* @param key - argument name.
|
|
13429
|
+
* @returns whether its delimiter arrived and no content reader has reported an error for this value.
|
|
13430
|
+
*/
|
|
13431
|
+
complete(key) {
|
|
13432
|
+
return this.remember("complete", key, () => this.completeNow(key));
|
|
13433
|
+
}
|
|
13434
|
+
/**
|
|
13435
|
+
* Read string length without materializing its text.
|
|
13436
|
+
* @param key - argument name.
|
|
13437
|
+
* @param options - change granularity for a streaming string.
|
|
13438
|
+
* @returns decoded UTF-16 length of the string field so far; undefined when absent or not a string.
|
|
13439
|
+
*/
|
|
13440
|
+
stringLength(key, options) {
|
|
13441
|
+
const step = Math.max(1, Math.floor(options?.step ?? 1));
|
|
13442
|
+
const offset = options?.offset ?? 0;
|
|
13443
|
+
return this.remember(`length:${step}:${offset}`, key, () => this.lengthNow(key), (length) => length === void 0 ? void 0 : Math.ceil((length + offset) / step));
|
|
13444
|
+
}
|
|
13445
|
+
/**
|
|
13446
|
+
* Check a string against a decoded UTF-16 length limit without materializing it.
|
|
13447
|
+
* @param key - argument name.
|
|
13448
|
+
* @param maxLength - decoded UTF-16 limit, floored to at least zero.
|
|
13449
|
+
* @returns whether the string is longer than the limit; false when absent or not a string.
|
|
13450
|
+
*/
|
|
13451
|
+
stringExceeds(key, maxLength) {
|
|
13452
|
+
const limit = Math.max(0, Math.floor(maxLength));
|
|
13453
|
+
return this.remember(`exceeds:${limit}`, key, () => (this.lengthNow(key, limit + 1) ?? 0) > limit);
|
|
13454
|
+
}
|
|
13455
|
+
/**
|
|
13456
|
+
* Read a decoded string, including a streaming prefix.
|
|
13457
|
+
* @param key - argument name.
|
|
13458
|
+
* @returns the string field's decoded text so far; undefined when absent or not a string.
|
|
13459
|
+
*/
|
|
13460
|
+
text(key) {
|
|
13461
|
+
return this.remember("text", key, () => this.textNow(key));
|
|
13462
|
+
}
|
|
13463
|
+
/**
|
|
13464
|
+
* Read at most the first decoded UTF-16 units of a string.
|
|
13465
|
+
* @param key - argument name.
|
|
13466
|
+
* @param maxLength - maximum decoded UTF-16 length, floored to at least one.
|
|
13467
|
+
* @returns the bounded string prefix; undefined when absent or not a string.
|
|
13468
|
+
*/
|
|
13469
|
+
textPrefix(key, maxLength) {
|
|
13470
|
+
const limit = Math.max(1, Math.floor(maxLength));
|
|
13471
|
+
return this.remember(`prefix:${limit}`, key, () => this.textPrefixNow(key, limit));
|
|
13472
|
+
}
|
|
13473
|
+
/**
|
|
13474
|
+
* Read a completed non-string argument.
|
|
13475
|
+
* @param key - argument name.
|
|
13476
|
+
* @returns the parsed non-string value once it closed; undefined while open, absent, or a string.
|
|
13477
|
+
*/
|
|
13478
|
+
value(key) {
|
|
13479
|
+
return this.remember("value", key, () => this.valueNow(key));
|
|
13480
|
+
}
|
|
13481
|
+
/** Answer a question and, on a streaming view, remember it for change detection. */
|
|
13482
|
+
remember(kind, key, read, comparison) {
|
|
13483
|
+
this.scan();
|
|
13484
|
+
const result = read();
|
|
13485
|
+
if (!this.sealed) {
|
|
13486
|
+
const id = `${kind}/${key}`;
|
|
13487
|
+
if (!this.#reads.has(id)) this.#reads.set(id, {
|
|
13488
|
+
completion: kind === "complete",
|
|
13489
|
+
answer: comparison === void 0 ? read : () => comparison(read()),
|
|
13490
|
+
last: comparison === void 0 ? result : comparison(result)
|
|
13491
|
+
});
|
|
13492
|
+
}
|
|
13493
|
+
return result;
|
|
13494
|
+
}
|
|
13495
|
+
closedNow() {
|
|
13496
|
+
return this.sealed || this.#mode === "closed" || this.#mode === "invalid";
|
|
13497
|
+
}
|
|
13498
|
+
keysNow() {
|
|
13499
|
+
return this.object === void 0 ? this.#order : Object.keys(this.object);
|
|
13500
|
+
}
|
|
13501
|
+
hasNow(key) {
|
|
13502
|
+
return this.object === void 0 ? this.#entries.has(key) : Object.hasOwn(this.object, key);
|
|
13503
|
+
}
|
|
13504
|
+
completeNow(key) {
|
|
13505
|
+
if (this.object !== void 0) return Object.hasOwn(this.object, key);
|
|
13506
|
+
const entry = this.#entries.get(key);
|
|
13507
|
+
return entry !== void 0 && entry.end >= 0 && (entry.kind === "string" ? entry.invalidAt === void 0 : !entry.invalid);
|
|
13508
|
+
}
|
|
13509
|
+
lengthNow(key, limit = Number.POSITIVE_INFINITY) {
|
|
13510
|
+
if (this.object !== void 0) {
|
|
13511
|
+
const field = Object.hasOwn(this.object, key) ? this.object[key] : void 0;
|
|
13512
|
+
return typeof field === "string" ? field.length : void 0;
|
|
13513
|
+
}
|
|
13514
|
+
const entry = this.#entries.get(key);
|
|
13515
|
+
if (entry?.kind !== "string") return void 0;
|
|
13516
|
+
if (entry.text !== void 0 && entry.text.at === entry.end) return entry.text.length;
|
|
13517
|
+
const read = entry.length ??= {
|
|
13518
|
+
at: entry.start,
|
|
13519
|
+
length: 0,
|
|
13520
|
+
text: ""
|
|
13521
|
+
};
|
|
13522
|
+
this.readString(entry, read, limit, false);
|
|
13523
|
+
return read.length;
|
|
13524
|
+
}
|
|
13525
|
+
textNow(key) {
|
|
13526
|
+
if (this.object !== void 0) {
|
|
13527
|
+
const field = Object.hasOwn(this.object, key) ? this.object[key] : void 0;
|
|
13528
|
+
return typeof field === "string" ? field : void 0;
|
|
13529
|
+
}
|
|
13530
|
+
const entry = this.#entries.get(key);
|
|
13531
|
+
if (entry?.kind !== "string") return void 0;
|
|
13532
|
+
if (entry.text === void 0 && entry.end >= 0 && entry.needsDecoding && entry.invalidAt === void 0) {
|
|
13533
|
+
let text;
|
|
13534
|
+
try {
|
|
13535
|
+
text = JSON.parse(`"${this.slice(entry.start, entry.end)}"`);
|
|
13536
|
+
} catch (_error) {}
|
|
13537
|
+
if (text !== void 0) entry.text = {
|
|
13538
|
+
at: entry.end,
|
|
13539
|
+
length: text.length,
|
|
13540
|
+
text
|
|
13541
|
+
};
|
|
13542
|
+
}
|
|
13543
|
+
const read = entry.text ??= {
|
|
13544
|
+
at: entry.start,
|
|
13545
|
+
length: 0,
|
|
13546
|
+
text: ""
|
|
13547
|
+
};
|
|
13548
|
+
this.readString(entry, read, Number.POSITIVE_INFINITY, true);
|
|
13549
|
+
return read.text;
|
|
13550
|
+
}
|
|
13551
|
+
textPrefixNow(key, maxLength) {
|
|
13552
|
+
if (this.object !== void 0) {
|
|
13553
|
+
const field = Object.hasOwn(this.object, key) ? this.object[key] : void 0;
|
|
13554
|
+
return typeof field === "string" ? field.slice(0, maxLength) : void 0;
|
|
13555
|
+
}
|
|
13556
|
+
const entry = this.#entries.get(key);
|
|
13557
|
+
if (entry?.kind !== "string") return void 0;
|
|
13558
|
+
const prefixes = entry.prefixes ??= /* @__PURE__ */ new Map();
|
|
13559
|
+
let read = prefixes.get(maxLength);
|
|
13560
|
+
if (read === void 0) {
|
|
13561
|
+
read = {
|
|
13562
|
+
at: entry.start,
|
|
13563
|
+
length: 0,
|
|
13564
|
+
text: ""
|
|
13565
|
+
};
|
|
13566
|
+
prefixes.set(maxLength, read);
|
|
13567
|
+
}
|
|
13568
|
+
this.readString(entry, read, maxLength, true);
|
|
13569
|
+
return read.text;
|
|
13570
|
+
}
|
|
13571
|
+
valueNow(key) {
|
|
13572
|
+
if (this.object !== void 0) {
|
|
13573
|
+
if (!Object.hasOwn(this.object, key)) return void 0;
|
|
13574
|
+
const field = this.object[key];
|
|
13575
|
+
return typeof field === "string" ? void 0 : field;
|
|
13576
|
+
}
|
|
13577
|
+
const entry = this.#entries.get(key);
|
|
13578
|
+
if (entry?.kind !== "value" || entry.end < 0 || entry.invalid) return void 0;
|
|
13579
|
+
if (entry.parsed === void 0) try {
|
|
13580
|
+
entry.parsed = JSON.parse(this.slice(entry.start, entry.end));
|
|
13581
|
+
} catch (_error) {
|
|
13582
|
+
entry.invalid = true;
|
|
13583
|
+
this.#invalidValue = true;
|
|
13584
|
+
}
|
|
13585
|
+
return entry.parsed;
|
|
13586
|
+
}
|
|
13587
|
+
chunkAt(at) {
|
|
13588
|
+
let low = 0;
|
|
13589
|
+
let high = this.#ends.length;
|
|
13590
|
+
while (low < high) {
|
|
13591
|
+
const mid = low + high >>> 1;
|
|
13592
|
+
if (this.#ends[mid] <= at) low = mid + 1;
|
|
13593
|
+
else high = mid;
|
|
13594
|
+
}
|
|
13595
|
+
return low;
|
|
13596
|
+
}
|
|
13597
|
+
/** Materialize only a requested range, never the cumulative source. */
|
|
13598
|
+
slice(start, end) {
|
|
13599
|
+
if (start >= end) return "";
|
|
13600
|
+
const first = this.chunkAt(start);
|
|
13601
|
+
const last = this.chunkAt(end - 1);
|
|
13602
|
+
const base = first === 0 ? 0 : this.#ends[first - 1];
|
|
13603
|
+
if (first === last) return this.chunks[first].slice(start - base, end - base);
|
|
13604
|
+
const parts = [this.chunks[first].slice(start - base)];
|
|
13605
|
+
for (let i = first + 1; i < last; i++) parts.push(this.chunks[i]);
|
|
13606
|
+
parts.push(this.chunks[last].slice(0, end - this.#ends[last - 1]));
|
|
13607
|
+
return parts.join("");
|
|
13608
|
+
}
|
|
13609
|
+
readString(entry, read, limit, materialize) {
|
|
13610
|
+
const end = Math.min(entry.end < 0 ? this.#consumed : entry.end, entry.invalidAt ?? Number.POSITIVE_INFINITY, this.#invalidAt ?? Number.POSITIVE_INFINITY);
|
|
13611
|
+
if (!entry.needsDecoding) {
|
|
13612
|
+
const length = Math.min(end - read.at, limit - read.length);
|
|
13613
|
+
if (length <= 0) return;
|
|
13614
|
+
if (materialize) read.text += this.slice(read.at, read.at + length);
|
|
13615
|
+
read.at += length;
|
|
13616
|
+
read.length += length;
|
|
13617
|
+
return;
|
|
13618
|
+
}
|
|
13619
|
+
let chunkIndex = this.chunkAt(read.at);
|
|
13620
|
+
while (read.at < end && read.length < limit) {
|
|
13621
|
+
const base = chunkIndex === 0 ? 0 : this.#ends[chunkIndex - 1];
|
|
13622
|
+
const chunk = this.chunks[chunkIndex];
|
|
13623
|
+
const remaining = chunk.slice(read.at - base, Math.min(chunk.length, end - base));
|
|
13624
|
+
const boundary = remaining.search(CONTENT_ESCAPE);
|
|
13625
|
+
const length = Math.min(boundary < 0 ? remaining.length : boundary, limit - read.length);
|
|
13626
|
+
if (length > 0) {
|
|
13627
|
+
if (materialize) read.text += remaining.slice(0, length);
|
|
13628
|
+
read.at += length;
|
|
13629
|
+
read.length += length;
|
|
13630
|
+
if (read.at === base + chunk.length) chunkIndex++;
|
|
13631
|
+
continue;
|
|
13632
|
+
}
|
|
13633
|
+
const type = remaining.length > 1 ? remaining[1] : read.at + 1 < end ? this.chunks[chunkIndex + 1][0] : void 0;
|
|
13634
|
+
let decoded;
|
|
13635
|
+
let width = 2;
|
|
13636
|
+
if (remaining[0] === "\\" && type === void 0 && entry.end < 0) return;
|
|
13637
|
+
if (remaining[0] === "\\" && type === "u") {
|
|
13638
|
+
const hex = this.slice(read.at + 2, Math.min(end, read.at + 6));
|
|
13639
|
+
let valid = true;
|
|
13640
|
+
for (let i = 0; i < hex.length; i++) if (!isHex(hex[i])) valid = false;
|
|
13641
|
+
if (valid) {
|
|
13642
|
+
if (hex.length < 4 && entry.end < 0) return;
|
|
13643
|
+
if (hex.length === 4) decoded = String.fromCharCode(Number.parseInt(hex, 16));
|
|
13644
|
+
}
|
|
13645
|
+
width = 6;
|
|
13646
|
+
} else if (remaining[0] === "\\" && type !== void 0) decoded = SIMPLE_ESCAPES[type];
|
|
13647
|
+
if (decoded === void 0) {
|
|
13648
|
+
entry.invalidAt = read.at;
|
|
13649
|
+
this.#invalidValue = true;
|
|
13650
|
+
return;
|
|
13651
|
+
}
|
|
13652
|
+
if (materialize) read.text += decoded;
|
|
13653
|
+
read.length++;
|
|
13654
|
+
read.at += width;
|
|
13655
|
+
while (chunkIndex < this.chunks.length && read.at >= this.#ends[chunkIndex]) chunkIndex++;
|
|
13656
|
+
}
|
|
13657
|
+
}
|
|
13658
|
+
/** Locate new field ranges without decoding or parsing their contents. */
|
|
13659
|
+
scan() {
|
|
13660
|
+
if (this.object !== void 0 || this.#consumed === this.#size) return;
|
|
13661
|
+
for (let i = this.chunkAt(this.#consumed); i < this.chunks.length && this.#invalidAt === void 0; i++) {
|
|
13662
|
+
const pending = this.chunks[i];
|
|
13663
|
+
const base = i === 0 ? 0 : this.#ends[i - 1];
|
|
13664
|
+
for (let index = this.#consumed - base; index < pending.length && this.#mode !== "invalid"; index++) {
|
|
13665
|
+
if (this.#mode === "string" || this.#mode === "nested" && this.#nestedInString) {
|
|
13666
|
+
const end = this.stringBoundary(pending, index);
|
|
13667
|
+
this.#consumed += end - index;
|
|
13668
|
+
index = end;
|
|
13669
|
+
if (index === pending.length) break;
|
|
13670
|
+
}
|
|
13671
|
+
this.step(pending[index], this.#consumed);
|
|
13672
|
+
this.#consumed++;
|
|
13673
|
+
}
|
|
13674
|
+
}
|
|
13675
|
+
}
|
|
13676
|
+
/** Only raw quotes and their preceding backslash runs can terminate a string. */
|
|
13677
|
+
stringBoundary(fragment, start) {
|
|
13678
|
+
let at = start;
|
|
13679
|
+
while (true) {
|
|
13680
|
+
const quote = fragment.indexOf("\"", at);
|
|
13681
|
+
const end = quote < 0 ? fragment.length : quote;
|
|
13682
|
+
if (this.#mode === "string") {
|
|
13683
|
+
const entry = this.#current;
|
|
13684
|
+
if (!entry.needsDecoding && CONTENT_ESCAPE.test(fragment.slice(at, end))) entry.needsDecoding = true;
|
|
13685
|
+
}
|
|
13686
|
+
let slashStart = end;
|
|
13687
|
+
while (slashStart > at && fragment[slashStart - 1] === "\\") slashStart--;
|
|
13688
|
+
const escaped = (end - slashStart) % 2 === 1 !== (slashStart === at && this.#escape);
|
|
13689
|
+
this.#escape = quote < 0 && escaped;
|
|
13690
|
+
if (quote < 0 || !escaped) return end;
|
|
13691
|
+
at = quote + 1;
|
|
13692
|
+
}
|
|
13693
|
+
}
|
|
13694
|
+
step(c, at) {
|
|
13695
|
+
switch (this.#mode) {
|
|
13696
|
+
case "root":
|
|
13697
|
+
if (isWhitespace(c)) return;
|
|
13698
|
+
if (c === "{") {
|
|
13699
|
+
this.#mode = "key-or-end";
|
|
13700
|
+
return;
|
|
13701
|
+
}
|
|
13702
|
+
this.fail();
|
|
13703
|
+
return;
|
|
13704
|
+
case "key-or-end":
|
|
13705
|
+
if (isWhitespace(c)) return;
|
|
13706
|
+
if (c === "}") {
|
|
13707
|
+
this.#mode = "closed";
|
|
13708
|
+
return;
|
|
13709
|
+
}
|
|
13710
|
+
if (c === "\"") {
|
|
13711
|
+
this.beginKey(at);
|
|
13712
|
+
return;
|
|
13713
|
+
}
|
|
13714
|
+
this.fail();
|
|
13715
|
+
return;
|
|
13716
|
+
case "key-only":
|
|
13717
|
+
if (isWhitespace(c)) return;
|
|
13718
|
+
if (c === "\"") {
|
|
13719
|
+
this.beginKey(at);
|
|
13720
|
+
return;
|
|
13721
|
+
}
|
|
13722
|
+
this.fail();
|
|
13723
|
+
return;
|
|
13724
|
+
case "key":
|
|
13725
|
+
this.stepKey(c, at);
|
|
13726
|
+
return;
|
|
13727
|
+
case "colon":
|
|
13728
|
+
if (isWhitespace(c)) return;
|
|
13729
|
+
if (c === ":") {
|
|
13730
|
+
this.#mode = "value";
|
|
13731
|
+
return;
|
|
13732
|
+
}
|
|
13733
|
+
this.fail();
|
|
13734
|
+
return;
|
|
13735
|
+
case "value":
|
|
13736
|
+
this.beginValue(c, at);
|
|
13737
|
+
return;
|
|
13738
|
+
case "string": {
|
|
13739
|
+
const entry = this.#current;
|
|
13740
|
+
entry.end = at;
|
|
13741
|
+
this.#current = null;
|
|
13742
|
+
this.#mode = "comma-or-end";
|
|
13743
|
+
return;
|
|
13744
|
+
}
|
|
13745
|
+
case "scalar":
|
|
13746
|
+
this.stepScalar(c, at);
|
|
13747
|
+
return;
|
|
13748
|
+
case "nested":
|
|
13749
|
+
this.stepNested(c, at);
|
|
13750
|
+
return;
|
|
13751
|
+
case "comma-or-end":
|
|
13752
|
+
if (isWhitespace(c)) return;
|
|
13753
|
+
if (c === ",") {
|
|
13754
|
+
this.#mode = "key-only";
|
|
13755
|
+
return;
|
|
13756
|
+
}
|
|
13757
|
+
if (c === "}") {
|
|
13758
|
+
this.#mode = "closed";
|
|
13759
|
+
return;
|
|
13760
|
+
}
|
|
13761
|
+
this.fail();
|
|
13762
|
+
return;
|
|
13763
|
+
case "closed":
|
|
13764
|
+
if (isWhitespace(c)) return;
|
|
13765
|
+
this.fail();
|
|
13766
|
+
return;
|
|
13767
|
+
case "invalid": return;
|
|
13768
|
+
default: assertNever$1(this.#mode);
|
|
13769
|
+
}
|
|
13770
|
+
}
|
|
13771
|
+
fail() {
|
|
13772
|
+
this.#invalidAt = this.#consumed;
|
|
13773
|
+
this.#mode = "invalid";
|
|
13774
|
+
this.#current = null;
|
|
13775
|
+
}
|
|
13776
|
+
beginKey(at) {
|
|
13777
|
+
this.#mode = "key";
|
|
13778
|
+
this.#keyStart = at + 1;
|
|
13779
|
+
this.#keyEscaped = false;
|
|
13780
|
+
this.#escape = false;
|
|
13781
|
+
}
|
|
13782
|
+
stepKey(c, at) {
|
|
13783
|
+
if (c < " ") {
|
|
13784
|
+
this.fail();
|
|
13785
|
+
return;
|
|
13786
|
+
}
|
|
13787
|
+
if (this.#escape) {
|
|
13788
|
+
this.#escape = false;
|
|
13789
|
+
return;
|
|
13790
|
+
}
|
|
13791
|
+
if (c === "\\") {
|
|
13792
|
+
this.#escape = true;
|
|
13793
|
+
this.#keyEscaped = true;
|
|
13794
|
+
return;
|
|
13795
|
+
}
|
|
13796
|
+
if (c !== "\"") return;
|
|
13797
|
+
const raw = this.slice(this.#keyStart, at);
|
|
13798
|
+
if (this.#keyEscaped) try {
|
|
13799
|
+
this.#key = JSON.parse(`"${raw}"`);
|
|
13800
|
+
} catch (_error) {
|
|
13801
|
+
this.fail();
|
|
13802
|
+
return;
|
|
13803
|
+
}
|
|
13804
|
+
else this.#key = raw;
|
|
13805
|
+
this.#mode = "colon";
|
|
13806
|
+
}
|
|
13807
|
+
open(entry) {
|
|
13808
|
+
if (!this.#entries.has(this.#key)) this.#order.push(this.#key);
|
|
13809
|
+
this.#entries.set(this.#key, entry);
|
|
13810
|
+
this.#current = entry;
|
|
13811
|
+
}
|
|
13812
|
+
beginValue(c, at) {
|
|
13813
|
+
if (isWhitespace(c)) return;
|
|
13814
|
+
if (c === "\"") {
|
|
13815
|
+
this.open({
|
|
13816
|
+
kind: "string",
|
|
13817
|
+
start: at + 1,
|
|
13818
|
+
end: -1,
|
|
13819
|
+
needsDecoding: false,
|
|
13820
|
+
invalidAt: void 0,
|
|
13821
|
+
length: void 0,
|
|
13822
|
+
text: void 0,
|
|
13823
|
+
prefixes: void 0
|
|
13824
|
+
});
|
|
13825
|
+
this.#escape = false;
|
|
13826
|
+
this.#mode = "string";
|
|
13827
|
+
return;
|
|
13828
|
+
}
|
|
13829
|
+
if (c === "}" || c === "," || c === ":" || c === "]") {
|
|
13830
|
+
this.fail();
|
|
13831
|
+
return;
|
|
13832
|
+
}
|
|
13833
|
+
this.open({
|
|
13834
|
+
kind: "value",
|
|
13835
|
+
start: at,
|
|
13836
|
+
end: -1,
|
|
13837
|
+
parsed: void 0,
|
|
13838
|
+
invalid: false
|
|
13839
|
+
});
|
|
13840
|
+
if (c === "{" || c === "[") {
|
|
13841
|
+
this.#mode = "nested";
|
|
13842
|
+
this.#nestedEnds = [c === "{" ? "}" : "]"];
|
|
13843
|
+
this.#nestedInString = false;
|
|
13844
|
+
this.#escape = false;
|
|
13845
|
+
return;
|
|
13846
|
+
}
|
|
13847
|
+
this.#mode = "scalar";
|
|
13848
|
+
}
|
|
13849
|
+
stepScalar(c, at) {
|
|
13850
|
+
if (c !== "," && c !== "}" && !isWhitespace(c)) return;
|
|
13851
|
+
this.closeValue(at);
|
|
13852
|
+
this.#mode = c === "," ? "key-only" : c === "}" ? "closed" : "comma-or-end";
|
|
13853
|
+
}
|
|
13854
|
+
stepNested(c, at) {
|
|
13855
|
+
if (this.#nestedInString) {
|
|
13856
|
+
this.#nestedInString = false;
|
|
13857
|
+
return;
|
|
13858
|
+
}
|
|
13859
|
+
if (c === "\"") {
|
|
13860
|
+
this.#nestedInString = true;
|
|
13861
|
+
return;
|
|
13862
|
+
}
|
|
13863
|
+
if (c === "{" || c === "[") {
|
|
13864
|
+
this.#nestedEnds.push(c === "{" ? "}" : "]");
|
|
13865
|
+
return;
|
|
13866
|
+
}
|
|
13867
|
+
if (c === "}" || c === "]") {
|
|
13868
|
+
if (this.#nestedEnds.pop() !== c) {
|
|
13869
|
+
this.fail();
|
|
13870
|
+
return;
|
|
13871
|
+
}
|
|
13872
|
+
if (this.#nestedEnds.length === 0) {
|
|
13873
|
+
this.closeValue(at + 1);
|
|
13874
|
+
this.#mode = "comma-or-end";
|
|
13875
|
+
}
|
|
13876
|
+
}
|
|
13877
|
+
}
|
|
13878
|
+
closeValue(end) {
|
|
13879
|
+
const entry = this.#current;
|
|
13880
|
+
entry.end = end;
|
|
13881
|
+
this.#current = null;
|
|
13882
|
+
}
|
|
13883
|
+
});
|
|
13884
|
+
/**
|
|
13885
|
+
* Mark an unreachable closed-union branch.
|
|
13886
|
+
* @param value - impossible value; an unhandled typed variant fails at the call site.
|
|
13887
|
+
* @param context - optional switch-site label included in the failure message.
|
|
13888
|
+
* @returns never; a runtime value that escaped its type always throws.
|
|
13889
|
+
*/
|
|
13890
|
+
function assertNever$1(value, context) {
|
|
13891
|
+
const rendered = JSON.stringify(value) ?? String(value);
|
|
13892
|
+
throw new Error(`unreachable variant${context ? ` in ${context}` : ""}: ${rendered}`);
|
|
13893
|
+
}
|
|
13894
|
+
/** Whether a path uses a Windows drive or UNC prefix. */
|
|
13895
|
+
function isWindowsStylePath(value) {
|
|
13896
|
+
return /^[A-Za-z]:[/\\]/.test(value) || value.startsWith("\\\\");
|
|
13897
|
+
}
|
|
13898
|
+
/**
|
|
13899
|
+
* Abbreviate a POSIX home directory for display.
|
|
13900
|
+
* @param path - Absolute or already-short display path.
|
|
13901
|
+
* @param home - Host account home; absent skips abbreviation.
|
|
13902
|
+
* @returns `~` or `~/…` for the POSIX home and its descendants, otherwise `path`.
|
|
13903
|
+
*/
|
|
13904
|
+
function abbreviateHomePath(path, home) {
|
|
13905
|
+
if (home === void 0 || home === "") return path;
|
|
13906
|
+
if (isWindowsStylePath(path) || isWindowsStylePath(home)) return path;
|
|
13907
|
+
const root = home.replace(/\/+$/, "");
|
|
13908
|
+
if (root === "" || root === "/") return path;
|
|
13909
|
+
if (path.replace(/\/+$/, "") === root) return "~";
|
|
13910
|
+
if (path.startsWith(`${root}/`)) return `~${path.slice(root.length)}`;
|
|
13911
|
+
return path;
|
|
13912
|
+
}
|
|
13913
|
+
/**
|
|
13914
|
+
* Read the final non-empty segment of a Workspace path for display.
|
|
13915
|
+
* Workspace-label surfaces use this helper instead of deriving another basename.
|
|
13916
|
+
* @param path - Workspace directory path using POSIX or Windows separators.
|
|
13917
|
+
* @returns the final segment, or an empty string for a separator-only path.
|
|
13918
|
+
*/
|
|
13919
|
+
function workspaceTitleOf(path) {
|
|
13920
|
+
const trimmed = path.replace(/[/\\]+$/, "");
|
|
13921
|
+
const separator = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
13922
|
+
return trimmed.slice(separator + 1);
|
|
13923
|
+
}
|
|
13924
|
+
/**
|
|
13925
|
+
* Resolve the Workspace browser group that owns one Session.
|
|
13926
|
+
* @param workspaces - authoritative Workspace membership.
|
|
13927
|
+
* @param sessionId - Session whose browser group is required.
|
|
13928
|
+
* @returns owning Workspace id, or {@link UNGROUPED_KEY} when no Workspace accounts for it.
|
|
13929
|
+
*/
|
|
13930
|
+
function owningGroupKey(workspaces, sessionId) {
|
|
13931
|
+
return workspaces.find((workspace) => workspace.sessionIds.includes(sessionId))?.workspaceId ?? "";
|
|
13932
|
+
}
|
|
13933
|
+
function mainSessionId(list) {
|
|
13934
|
+
return Object.values(list.byId).find((session) => (session.retainedBy.mainView ?? 0) > 0)?.id;
|
|
13935
|
+
}
|
|
13936
|
+
/**
|
|
13937
|
+
* Directory display label: basename of the path (both separators accepted).
|
|
13938
|
+
* Ungrouped-bucket fallback for surfaces without a workspace title.
|
|
13939
|
+
* @param cwd - directory path, or undefined for the ungrouped bucket.
|
|
13940
|
+
* @returns basename, the raw cwd when it has no basename, or an empty ungrouped marker.
|
|
13941
|
+
*/
|
|
13942
|
+
function workspaceLabel(cwd) {
|
|
13943
|
+
if (cwd === void 0 || cwd === "") return "";
|
|
13944
|
+
const base = workspaceTitleOf(cwd);
|
|
13945
|
+
return base !== "" ? base : cwd;
|
|
13946
|
+
}
|
|
13947
|
+
/**
|
|
13948
|
+
* Project known account members by current Session recency.
|
|
13949
|
+
* @param sessionIds - authoritative account membership.
|
|
13950
|
+
* @param summaries - current Session summaries; members without a summary are omitted until it arrives.
|
|
13951
|
+
* @returns known members newest first, with Session identity as the deterministic tie-break.
|
|
13952
|
+
*/
|
|
13953
|
+
function orderByRecency(sessionIds, summaries) {
|
|
13954
|
+
return sessionIds.flatMap((id) => {
|
|
13955
|
+
const summary = summaries[id];
|
|
13956
|
+
if (summary === void 0) return [];
|
|
13957
|
+
return [{
|
|
13958
|
+
id,
|
|
13959
|
+
rank: summary.updatedAt
|
|
13960
|
+
}];
|
|
13961
|
+
}).sort((a, b) => {
|
|
13962
|
+
if (a.rank !== b.rank) return b.rank - a.rank;
|
|
13963
|
+
return a.id < b.id ? -1 : 1;
|
|
13964
|
+
}).map((member) => member.id);
|
|
13965
|
+
}
|
|
13966
|
+
/**
|
|
13967
|
+
* Reconcile a browser-local manual order with current account membership.
|
|
13968
|
+
* New ordinary forks precede their sources without changing saved entries' relative order.
|
|
13969
|
+
* @param memberIds - authoritative account membership.
|
|
13970
|
+
* @param savedOrder - previously saved browser-local order.
|
|
13971
|
+
* @param summaries - current Session metadata; unknown new members wait for their summaries.
|
|
13972
|
+
* @param rowState - global pin and archive membership; only account members can supplement the order.
|
|
13973
|
+
* @returns saved relative positions plus missing members ordered by pin, fork source, recency, and archive status.
|
|
13974
|
+
*/
|
|
13975
|
+
function reconcileManualOrder(memberIds, savedOrder, summaries, rowState) {
|
|
13976
|
+
const members = new Map(memberIds.map((id) => [id, id]));
|
|
13977
|
+
const included = /* @__PURE__ */ new Set();
|
|
13978
|
+
const ordered = [];
|
|
13979
|
+
for (const key of savedOrder ?? []) {
|
|
13980
|
+
const id = members.get(key);
|
|
13981
|
+
if (id === void 0 || included.has(key)) continue;
|
|
13982
|
+
ordered.push(id);
|
|
13983
|
+
included.add(key);
|
|
13984
|
+
}
|
|
13985
|
+
const archived = new Set(rowState?.archivedSessionIds);
|
|
13986
|
+
const pins = [];
|
|
13987
|
+
for (const sessionId of rowState?.pinnedSessionIds ?? []) {
|
|
13988
|
+
const id = members.get(sessionId);
|
|
13989
|
+
if (id === void 0 || included.has(id) || archived.has(id) || summaries[id] === void 0) continue;
|
|
13990
|
+
pins.push(id);
|
|
13991
|
+
included.add(id);
|
|
13992
|
+
}
|
|
13993
|
+
const ordinary = [];
|
|
13994
|
+
const archives = [];
|
|
13995
|
+
for (const id of orderByRecency([...members.values()].filter((id$1) => !included.has(id$1)), summaries)) if (archived.has(id)) archives.push(id);
|
|
13996
|
+
else ordinary.push(id);
|
|
13997
|
+
const result = [
|
|
13998
|
+
...pins,
|
|
13999
|
+
...ordered,
|
|
14000
|
+
...ordinary,
|
|
14001
|
+
...archives
|
|
14002
|
+
];
|
|
14003
|
+
const pending = new Set(ordinary);
|
|
14004
|
+
const placeFork = (id) => {
|
|
14005
|
+
if (!pending.delete(id)) return;
|
|
14006
|
+
const parentId = summaries[id]?.parentId;
|
|
14007
|
+
if (parentId === void 0 || parentId === id || !result.includes(parentId)) return;
|
|
14008
|
+
placeFork(parentId);
|
|
14009
|
+
result.splice(result.indexOf(id), 1);
|
|
14010
|
+
result.splice(result.indexOf(parentId), 0, id);
|
|
14011
|
+
};
|
|
14012
|
+
for (const id of [...ordinary].reverse()) placeFork(id);
|
|
14013
|
+
return result;
|
|
14014
|
+
}
|
|
14015
|
+
/**
|
|
13348
14016
|
* Keep the selected provisional New Session ahead of either base order.
|
|
13349
14017
|
* @param order - recency or reconciled manual order.
|
|
13350
14018
|
* @param currentBlank - selected blank Session in this account, when present.
|
|
@@ -13760,6 +14428,7 @@ const official$2 = ((require$1) => {
|
|
|
13760
14428
|
sessions;
|
|
13761
14429
|
view;
|
|
13762
14430
|
notify;
|
|
14431
|
+
/** The latest in-flight connection per Workspace; a request joins it only when both name the same preset. */
|
|
13763
14432
|
connecting = /* @__PURE__ */ new Map();
|
|
13764
14433
|
lifetime = new AbortController();
|
|
13765
14434
|
selection = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({}, { persist: { name: "dsh.sessions.current" } });
|
|
@@ -13774,6 +14443,7 @@ const official$2 = ((require$1) => {
|
|
|
13774
14443
|
*/
|
|
13775
14444
|
constructor(ctx, directoryPicker, workspaces, sessions, view, notify) {
|
|
13776
14445
|
super(ctx, "uiWorkspace");
|
|
14446
|
+
this.managedWorktreeGuard = ctx.get("__dshGitWorktreeManagedGuard");
|
|
13777
14447
|
this.directoryPicker = directoryPicker;
|
|
13778
14448
|
this.workspaces = workspaces;
|
|
13779
14449
|
this.sessions = sessions;
|
|
@@ -13790,46 +14460,90 @@ const official$2 = ((require$1) => {
|
|
|
13790
14460
|
};
|
|
13791
14461
|
}, "ui-workspace: Workspace navigation policy");
|
|
13792
14462
|
}
|
|
13793
|
-
|
|
14463
|
+
connectWorkspace(workspaceId, options = {}) {
|
|
14464
|
+
return this.connectBlank(workspaceId, options);
|
|
14465
|
+
}
|
|
14466
|
+
/**
|
|
14467
|
+
* @param reuse - preset for the reused or created blank; absent creates a fresh Session.
|
|
14468
|
+
*/
|
|
14469
|
+
async connectBlank(workspaceId, reuse) {
|
|
13794
14470
|
const workspace = this.workspaces.list.getSnapshot().items.find((item) => item.workspaceId === workspaceId);
|
|
13795
14471
|
if (workspace === void 0) throw new Error(`uiWorkspace.connectWorkspace: unknown workspace ${workspaceId}`);
|
|
14472
|
+
if (reuse === void 0) return this.sessions.create({ workspaceId });
|
|
13796
14473
|
const inflight = this.connecting.get(workspaceId);
|
|
13797
|
-
if (inflight !== void 0) return inflight;
|
|
13798
|
-
const attempt$1 = this.
|
|
13799
|
-
this.connecting.delete(workspaceId);
|
|
14474
|
+
if (inflight !== void 0 && inflight.agentPreset === reuse.agentPreset) return inflight.attempt;
|
|
14475
|
+
const attempt$1 = this.createInWorkspace(workspace, reuse).finally(() => {
|
|
14476
|
+
if (this.connecting.get(workspaceId)?.attempt === attempt$1) this.connecting.delete(workspaceId);
|
|
14477
|
+
});
|
|
14478
|
+
this.connecting.set(workspaceId, {
|
|
14479
|
+
agentPreset: reuse.agentPreset,
|
|
14480
|
+
attempt: attempt$1
|
|
13800
14481
|
});
|
|
13801
|
-
this.connecting.set(workspaceId, attempt$1);
|
|
13802
14482
|
return attempt$1;
|
|
13803
14483
|
}
|
|
13804
|
-
|
|
14484
|
+
createInWorkspace(workspace, options) {
|
|
13805
14485
|
const archived = this.workspaces.list.getSnapshot().archivedSessionIds;
|
|
13806
14486
|
const sessions = this.sessions.list.getSnapshot();
|
|
13807
|
-
|
|
14487
|
+
const blank = sessions.ids.find((id) => {
|
|
13808
14488
|
const summary = sessions.byId[id];
|
|
13809
|
-
|
|
13810
|
-
|
|
13811
|
-
|
|
13812
|
-
|
|
14489
|
+
return summary !== void 0 && summary.blank && summary.cwd === workspace.path && workspace.sessionIds.includes(id) && !archived.includes(id);
|
|
14490
|
+
});
|
|
14491
|
+
return this.createNamed({
|
|
14492
|
+
workspaceId: workspace.workspaceId,
|
|
14493
|
+
...blank === void 0 ? {} : { sessionId: blank },
|
|
14494
|
+
...options.agentPreset === void 0 ? {} : { agentPreset: options.agentPreset }
|
|
14495
|
+
});
|
|
13813
14496
|
}
|
|
13814
|
-
|
|
14497
|
+
/**
|
|
14498
|
+
* Create through the Host. A named blank the Host declined may still read as
|
|
14499
|
+
* blank from stale cached list metadata, which hides it from the Session tree;
|
|
14500
|
+
* its projections are reloaded so the row reflects its log.
|
|
14501
|
+
*/
|
|
14502
|
+
async createNamed(request) {
|
|
14503
|
+
const sessionId = await this.sessions.create(request);
|
|
14504
|
+
const named = request.sessionId;
|
|
14505
|
+
if (named !== void 0 && named !== sessionId) this.sessions.refreshProjections(named).catch((reason) => {
|
|
14506
|
+
console.warn("declined blank Session projection reload failed:", reason);
|
|
14507
|
+
});
|
|
14508
|
+
return sessionId;
|
|
14509
|
+
}
|
|
14510
|
+
/**
|
|
14511
|
+
* Reopen a saved blank Session under the preset its log recorded, or under
|
|
14512
|
+
* the Host default once that preset no longer activates. Listed values are
|
|
14513
|
+
* cached hints that can lag the log after an unclean Host exit, so the
|
|
14514
|
+
* Session's projections are reloaded before the preset is read; a Session
|
|
14515
|
+
* that still awaits a format migration reloads only those cached hints.
|
|
14516
|
+
*/
|
|
14517
|
+
async restoreBlank(workspaceId, sessionId) {
|
|
14518
|
+
await this.sessions.refreshProjections(sessionId);
|
|
14519
|
+
const recorded = this.sessions.list.getSnapshot().byId[sessionId]?.projectionValues?.agentPreset;
|
|
14520
|
+
const request = {
|
|
14521
|
+
workspaceId,
|
|
14522
|
+
sessionId
|
|
14523
|
+
};
|
|
14524
|
+
if (typeof recorded !== "string") return this.createNamed(request);
|
|
13815
14525
|
try {
|
|
13816
|
-
return await this.
|
|
13817
|
-
|
|
13818
|
-
|
|
14526
|
+
return await this.createNamed({
|
|
14527
|
+
...request,
|
|
14528
|
+
agentPreset: recorded
|
|
13819
14529
|
});
|
|
13820
14530
|
} catch (error) {
|
|
13821
|
-
|
|
13822
|
-
|
|
14531
|
+
const code = sessionCreateErrorOf(error)?.rpcError.code;
|
|
14532
|
+
if (code !== "agent-preset/not-found" && code !== "agent-preset/invalid") throw error;
|
|
14533
|
+
return this.createNamed(request);
|
|
13823
14534
|
}
|
|
13824
14535
|
}
|
|
13825
14536
|
openSession(target) {
|
|
13826
14537
|
this.replaceMain(target, this.lifetime.signal, "reveal");
|
|
13827
14538
|
}
|
|
13828
|
-
|
|
14539
|
+
openWorkspace(workspaceId, beforeOpen, options = {}) {
|
|
14540
|
+
return this.openWorkspaceSession(workspaceId, beforeOpen, options);
|
|
14541
|
+
}
|
|
14542
|
+
async openWorkspaceSession(workspaceId, beforeOpen, reuse) {
|
|
13829
14543
|
const navigation = AbortSignal.any([this.ctx.layout.beginNavigation(), this.lifetime.signal]);
|
|
13830
14544
|
let sessionId;
|
|
13831
14545
|
try {
|
|
13832
|
-
sessionId = await this.
|
|
14546
|
+
sessionId = await this.connectBlank(workspaceId, reuse);
|
|
13833
14547
|
} catch (error) {
|
|
13834
14548
|
if (!navigation.aborted) this.notify({
|
|
13835
14549
|
kind: "createFailed",
|
|
@@ -13840,28 +14554,58 @@ const official$2 = ((require$1) => {
|
|
|
13840
14554
|
if (navigation.aborted) return;
|
|
13841
14555
|
this.replaceMain(sessionId, navigation, "reveal", beforeOpen);
|
|
13842
14556
|
}
|
|
13843
|
-
async forkSession(sessionId, onCreated) {
|
|
14557
|
+
async forkSession(sessionId, onCreated, options) {
|
|
14558
|
+
if (this.managedWorktreeGuard.blockSession(sessionId)) throw new Error("managed Session must be changed through its Worktree owner");
|
|
13844
14559
|
return this.sessions.fork({
|
|
13845
14560
|
sessionId,
|
|
13846
14561
|
increaseTitle: true,
|
|
13847
|
-
...onCreated === void 0 ? {} : { onCreated }
|
|
14562
|
+
...onCreated === void 0 ? {} : { onCreated },
|
|
14563
|
+
...options?.allowMigration === void 0 ? {} : { allowMigration: options.allowMigration }
|
|
13848
14564
|
});
|
|
13849
14565
|
}
|
|
13850
|
-
startSession(workspaceId) {
|
|
14566
|
+
startSession(workspaceId, options) {
|
|
14567
|
+
const { agentPreset, ...draft } = options ?? {};
|
|
14568
|
+
const draftOptions = options === void 0 ? void 0 : draft;
|
|
14569
|
+
const initializeDraft = draftOptions !== void 0 && (draftOptions.prompt !== void 0 || draftOptions.clearPreviousDraft === true);
|
|
13851
14570
|
const workspace = this.workspaces.list.getSnapshot();
|
|
13852
14571
|
const sessions = this.sessions.list.getSnapshot();
|
|
13853
14572
|
const current = this.mainReference?.sessionId;
|
|
13854
14573
|
const currentWorkspaceId = current === void 0 ? void 0 : workspace.items.find((item) => item.sessionIds.includes(current))?.workspaceId;
|
|
13855
14574
|
const recent = workspace.phase === "ready" && sessions.phase === "ready" ? recentWorkspace(workspace.items, sessions.byId) : void 0;
|
|
13856
14575
|
const target = workspaceId ?? currentWorkspaceId ?? recent;
|
|
14576
|
+
if (target !== void 0 && this.managedWorktreeGuard.blockWorkspace(target)) return;
|
|
13857
14577
|
if (target === void 0) {
|
|
14578
|
+
if (initializeDraft) {
|
|
14579
|
+
this.notify({
|
|
14580
|
+
kind: "createFailed",
|
|
14581
|
+
message: this.ctx.locale.bind("workspace")("draft.workspaceRequired")
|
|
14582
|
+
});
|
|
14583
|
+
return;
|
|
14584
|
+
}
|
|
13858
14585
|
this.clearMain();
|
|
13859
14586
|
return;
|
|
13860
14587
|
}
|
|
13861
|
-
this.
|
|
14588
|
+
(draftOptions === void 0 ? this.openWorkspaceSession(target, void 0, void 0) : this.openWorkspace(target, initializeDraft ? (id) => {
|
|
14589
|
+
const binding = this.sessions.binding(id);
|
|
14590
|
+
if (binding === void 0) this.draftPreparationFailed();
|
|
14591
|
+
this.prepareDraft(binding, draftOptions);
|
|
14592
|
+
} : void 0, agentPreset === void 0 ? {} : { agentPreset })).catch((reason) => {
|
|
13862
14593
|
console.warn("new session failed:", reason);
|
|
13863
14594
|
});
|
|
13864
14595
|
}
|
|
14596
|
+
prepareDraft(binding, options) {
|
|
14597
|
+
const conversation = this.ctx.get("conversation");
|
|
14598
|
+
if (conversation === void 0) this.draftPreparationFailed();
|
|
14599
|
+
if (conversation.input.requestDraftInitialization(binding, options) === "blocked") this.draftPreparationFailed();
|
|
14600
|
+
}
|
|
14601
|
+
draftPreparationFailed() {
|
|
14602
|
+
const message = this.ctx.locale.bind("workspace")("draft.initializationFailed");
|
|
14603
|
+
this.notify({
|
|
14604
|
+
kind: "createFailed",
|
|
14605
|
+
message
|
|
14606
|
+
});
|
|
14607
|
+
throw new Error(message);
|
|
14608
|
+
}
|
|
13865
14609
|
async archiveSession(sessionId, options = {}) {
|
|
13866
14610
|
await this.workspaces.archiveSession(sessionId, options);
|
|
13867
14611
|
if (this.mainReference?.sessionId === sessionId) this.clearMain();
|
|
@@ -13940,7 +14684,7 @@ const official$2 = ((require$1) => {
|
|
|
13940
14684
|
}
|
|
13941
14685
|
const navigation = AbortSignal.any([this.ctx.layout.beginNavigation(), this.lifetime.signal]);
|
|
13942
14686
|
let sessionId;
|
|
13943
|
-
if (summary !== void 0 && workspace !== void 0 && summary.cwd === workspace.path && !workspaces.archivedSessionIds.includes(summary.id)) sessionId = await this.
|
|
14687
|
+
if (summary !== void 0 && workspace !== void 0 && summary.cwd === workspace.path && !workspaces.archivedSessionIds.includes(summary.id)) sessionId = await this.restoreBlank(workspace.workspaceId, summary.id);
|
|
13944
14688
|
let target = workspace?.workspaceId ?? recentWorkspace(workspaces.items, sessions.byId);
|
|
13945
14689
|
if (target === void 0 && workspaces.items.length === 0 && sessions.ids.length === 0) {
|
|
13946
14690
|
const prepared = await this.initializeDefaultWorkspace(navigation);
|
|
@@ -14058,7 +14802,7 @@ const official$2 = ((require$1) => {
|
|
|
14058
14802
|
function workspaceDisplayTitle(title, localizedDefault) {
|
|
14059
14803
|
return title === "default-workspace" ? localizedDefault : title;
|
|
14060
14804
|
}
|
|
14061
|
-
const css$3 = ".YDXeBa_projectRow,.YDXeBa_sessionRow{border-radius:var(--dsw-radius-md);padding:0 8px;cursor:pointer;user-select:none;color:var(--dsw-alias-label-primary);align-items:center;gap:6px;padding-inline-start:calc(8px + var(--dsh-workspace-indent,0px));display:flex}.YDXeBa_projectRow:hover,.YDXeBa_sessionRow:hover,.YDXeBa_sessionRow.YDXeBa_selected{background:var(--dsw-alias-interactive-bg-hover)}.YDXeBa_searchResultRow{box-sizing:border-box;border-radius:var(--dsw-radius-lg);cursor:pointer;text-align:left;width:100%;min-height:48px;color:var(--dsw-alias-label-primary);background:0 0;border:none;flex-direction:column;align-items:stretch;padding:4px 8px;display:flex}.YDXeBa_searchResultRow:hover,.YDXeBa_searchResultRow.YDXeBa_selected{background:var(--dsw-alias-interactive-bg-hover)}.YDXeBa_searchResultHeading{align-items:center;min-width:0;display:flex}.YDXeBa_searchResultTitle{text-overflow:ellipsis;white-space:nowrap;flex:0 auto;min-width:0;margin-left:4px;font-size:14px;line-height:20px;overflow:hidden}.YDXeBa_searchResultMeta{align-items:center;gap:6px;min-width:0;margin-left:20px;display:flex}.YDXeBa_searchResultWorkspace,.YDXeBa_searchResultSnippet{text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:17px;overflow:hidden}.YDXeBa_searchResultWorkspace{max-width:40%;color:var(--dsw-alias-label-tertiary);flex:none}.YDXeBa_searchResultWorkspace:only-child{max-width:100%}.YDXeBa_searchResultSnippet{min-width:0;color:var(--dsw-alias-label-secondary);flex:1}.YDXeBa_projectRow{box-sizing:border-box;align-items:center;height:34px}.YDXeBa_projectRow .YDXeBa_rowActions{height:20px}.YDXeBa_sessionRow{gap:0;height:32px}.YDXeBa_sessionRow .YDXeBa_title{margin:0 6px 0 4px}.YDXeBa_slot{width:16px;height:20px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.YDXeBa_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.YDXeBa_folderActive{color:var(--dsw-alias-state-business-primary)}.YDXeBa_projectRow .YDXeBa_chevron{display:none}.YDXeBa_projectRow:hover .YDXeBa_chevron{display:inline-flex}.YDXeBa_projectRow:hover .YDXeBa_folder{display:none}.YDXeBa_arrow{transition:transform .15s var(--ds-ease-in-out)}.YDXeBa_arrowOpen{transform:rotate(90deg)}.YDXeBa_projectText{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.YDXeBa_title{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:14px;line-height:20px;overflow:hidden}.YDXeBa_renameInput{border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-button-elevated-fill);min-width:0;color:inherit;outline:none;padding:0 2px;font-size:14px;line-height:20px}.YDXeBa_sessionRow .YDXeBa_title{flex:1}.YDXeBa_sessionRow .YDXeBa_title[data-scrolled]{mask-image:linear-gradient(90deg,#0000,#000 12px)}.YDXeBa_sessionRow .YDXeBa_title[data-clipped]{mask-image:linear-gradient(270deg,#0000,#000 12px)}.YDXeBa_sessionRow .YDXeBa_title[data-scrolled][data-clipped]{mask-image:linear-gradient(90deg,#0000,#000 12px calc(100% - 12px),#0000)}.YDXeBa_meta{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:20px;overflow:hidden}.YDXeBa_time{color:var(--dsw-alias-label-tertiary);flex:none;font-size:10px;line-height:16px}.YDXeBa_pinIndicator{width:16px;height:20px;color:var(--dsw-alias-label-caption);flex:none;justify-content:center;align-items:center;margin-left:6px;display:inline-flex}.YDXeBa_sessionRow.YDXeBa_archived .YDXeBa_title,.YDXeBa_searchResultRow.YDXeBa_archived .YDXeBa_searchResultTitle,.YDXeBa_searchResultRow.YDXeBa_archived .YDXeBa_searchResultWorkspace,.YDXeBa_searchResultRow.YDXeBa_archived .YDXeBa_searchResultSnippet{color:var(--dsw-alias-label-caption)}.YDXeBa_dot{flex:none}.YDXeBa_rowActions{flex:none;align-items:center;gap:
|
|
14805
|
+
const css$3 = ".YDXeBa_projectRow,.YDXeBa_sessionRow{border-radius:var(--dsw-radius-md);padding:0 8px;cursor:pointer;user-select:none;color:var(--dsw-alias-label-primary);align-items:center;gap:6px;padding-inline-start:calc(8px + var(--dsh-workspace-indent,0px));display:flex}.YDXeBa_projectRow:hover,.YDXeBa_sessionRow:hover,.YDXeBa_sessionRow.YDXeBa_selected{background:var(--dsw-alias-interactive-bg-hover)}.YDXeBa_searchResultRow{box-sizing:border-box;border-radius:var(--dsw-radius-lg);cursor:pointer;text-align:left;width:100%;min-height:48px;color:var(--dsw-alias-label-primary);background:0 0;border:none;flex-direction:column;align-items:stretch;padding:4px 8px;display:flex}.YDXeBa_searchResultRow:hover,.YDXeBa_searchResultRow.YDXeBa_selected{background:var(--dsw-alias-interactive-bg-hover)}.YDXeBa_searchResultHeading{align-items:center;min-width:0;display:flex}.YDXeBa_searchResultTitle{text-overflow:ellipsis;white-space:nowrap;flex:0 auto;min-width:0;margin-left:4px;font-size:14px;line-height:20px;overflow:hidden}.YDXeBa_searchResultMeta{align-items:center;gap:6px;min-width:0;margin-left:20px;display:flex}.YDXeBa_searchResultWorkspace,.YDXeBa_searchResultSnippet{text-overflow:ellipsis;white-space:nowrap;font-size:12px;line-height:17px;overflow:hidden}.YDXeBa_searchResultWorkspace{max-width:40%;color:var(--dsw-alias-label-tertiary);flex:none}.YDXeBa_searchResultWorkspace:only-child{max-width:100%}.YDXeBa_searchResultSnippet{min-width:0;color:var(--dsw-alias-label-secondary);flex:1}.YDXeBa_projectRow{box-sizing:border-box;align-items:center;height:34px}.YDXeBa_projectRow .YDXeBa_rowActions{height:20px}.YDXeBa_sessionRow{gap:0;height:32px}.YDXeBa_sessionRow .YDXeBa_title{margin:0 6px 0 4px}.YDXeBa_slot{width:16px;height:20px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.YDXeBa_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.YDXeBa_folderActive{color:var(--dsw-alias-state-business-primary)}.YDXeBa_projectRow .YDXeBa_chevron{display:none}.YDXeBa_projectRow:hover .YDXeBa_chevron{display:inline-flex}.YDXeBa_projectRow:hover .YDXeBa_folder{display:none}.YDXeBa_arrow{transition:transform .15s var(--ds-ease-in-out)}.YDXeBa_arrowOpen{transform:rotate(90deg)}.YDXeBa_projectText{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.YDXeBa_title{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:14px;line-height:20px;overflow:hidden}.YDXeBa_renameInput{border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-button-elevated-fill);min-width:0;color:inherit;outline:none;padding:0 2px;font-size:14px;line-height:20px}.YDXeBa_sessionRow .YDXeBa_title{flex:1}.YDXeBa_sessionRow .YDXeBa_title[data-scrolled]{mask-image:linear-gradient(90deg,#0000,#000 12px)}.YDXeBa_sessionRow .YDXeBa_title[data-clipped]{mask-image:linear-gradient(270deg,#0000,#000 12px)}.YDXeBa_sessionRow .YDXeBa_title[data-scrolled][data-clipped]{mask-image:linear-gradient(90deg,#0000,#000 12px calc(100% - 12px),#0000)}.YDXeBa_meta{text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:20px;overflow:hidden}.YDXeBa_time{color:var(--dsw-alias-label-tertiary);flex:none;font-size:10px;line-height:16px}.YDXeBa_pinIndicator{width:16px;height:20px;color:var(--dsw-alias-label-caption);flex:none;justify-content:center;align-items:center;margin-left:6px;display:inline-flex}.YDXeBa_sessionRow.YDXeBa_archived .YDXeBa_title,.YDXeBa_searchResultRow.YDXeBa_archived .YDXeBa_searchResultTitle,.YDXeBa_searchResultRow.YDXeBa_archived .YDXeBa_searchResultWorkspace,.YDXeBa_searchResultRow.YDXeBa_archived .YDXeBa_searchResultSnippet{color:var(--dsw-alias-label-caption)}.YDXeBa_dot{flex:none}.YDXeBa_rowActions{flex:none;align-items:center;gap:15px;display:none}.YDXeBa_projectRow:hover .YDXeBa_rowActions,.YDXeBa_sessionRow:hover .YDXeBa_rowActions,.YDXeBa_searchResultRow:hover .YDXeBa_rowActions,.YDXeBa_projectRow.YDXeBa_menuOpen .YDXeBa_rowActions,.YDXeBa_sessionRow.YDXeBa_menuOpen .YDXeBa_rowActions{display:inline-flex}.YDXeBa_searchResultHeading .YDXeBa_rowActions{margin-left:auto}.YDXeBa_sessionRow:hover .YDXeBa_time,.YDXeBa_sessionRow.YDXeBa_menuOpen .YDXeBa_time,.YDXeBa_sessionRow:hover .YDXeBa_pinIndicator,.YDXeBa_sessionRow.YDXeBa_menuOpen .YDXeBa_pinIndicator{display:none}@media (hover:hover){.YDXeBa_sessionRow:hover .YDXeBa_title,.YDXeBa_sessionRow.YDXeBa_menuOpen .YDXeBa_title{text-overflow:clip}}.YDXeBa_projectRow.YDXeBa_menuOpen,.YDXeBa_sessionRow.YDXeBa_menuOpen{background:var(--dsw-alias-interactive-bg-hover)}.YDXeBa_sessionRow.YDXeBa_dropBefore,.YDXeBa_sessionRow.YDXeBa_dropAfter{position:relative}.YDXeBa_sessionRow.YDXeBa_dropBefore:before,.YDXeBa_sessionRow.YDXeBa_dropAfter:after{content:\"\";z-index:1;background:linear-gradient(55deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 0 / 5px 7px no-repeat, linear-gradient(125deg, transparent calc(50% - 1px), var(--dsw-alias-state-business-primary) calc(50% - 1px) calc(50% + 1px), transparent calc(50% + 1px)) 0 5px / 5px 7px no-repeat, linear-gradient(var(--dsw-alias-state-business-primary) 0 0) 4px 5px / calc(100% - 4px) 2px no-repeat;pointer-events:none;height:12px;position:absolute;left:0;right:4px}.YDXeBa_sessionRow.YDXeBa_dropBefore:before{top:-7px}.YDXeBa_sessionRow.YDXeBa_dropAfter:after{bottom:-7px}.YDXeBa_hoverContent{flex-direction:column;gap:8px;display:flex}.YDXeBa_hoverTitle{color:#fff;overflow-wrap:break-word;font-size:14px;line-height:20px}.YDXeBa_hoverPath{color:#cfd3d6;word-break:break-all;font-size:12px;line-height:16px}.YDXeBa_hoverTime{color:#cfd3d6;font-size:12px;line-height:16px}.YDXeBa_hoverStatus{color:#adb2b8;align-items:center;gap:8px;font-size:12px;line-height:20px;display:flex}.YDXeBa_hoverArchived svg{flex-shrink:0;margin:0 -4px}.YDXeBa_iconButton{border-radius:var(--dsw-radius-xs);cursor:pointer;width:16px;height:16px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.YDXeBa_iconButton:hover{color:var(--dsw-alias-label-primary)}.YDXeBa_chevron{color:var(--dsw-alias-label-caption)}@media (prefers-reduced-motion:reduce){.YDXeBa_arrow{transition:none;animation:none}}";
|
|
14062
14806
|
const tagId$3 = "@deepseek-ai/dsh-client-ui-workspace/Rows.module.css";
|
|
14063
14807
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
|
|
14064
14808
|
const tag = document.createElement("style");
|
|
@@ -14343,6 +15087,7 @@ const official$2 = ((require$1) => {
|
|
|
14343
15087
|
side: "bottom",
|
|
14344
15088
|
align: "end",
|
|
14345
15089
|
delayMs: 500,
|
|
15090
|
+
portal: true,
|
|
14346
15091
|
children: !protectedManagedWorkspace && (0, react_jsx_runtime$1.jsx)("button", {
|
|
14347
15092
|
type: "button",
|
|
14348
15093
|
className: Rows_module_css_default.iconButton,
|
|
@@ -14368,6 +15113,7 @@ const official$2 = ((require$1) => {
|
|
|
14368
15113
|
t
|
|
14369
15114
|
}),
|
|
14370
15115
|
openDelayMs: 800,
|
|
15116
|
+
grouped: true,
|
|
14371
15117
|
disabled: menuOpen,
|
|
14372
15118
|
copyText: row.cwd,
|
|
14373
15119
|
copyLabel: t("copy"),
|
|
@@ -14470,7 +15216,7 @@ const official$2 = ((require$1) => {
|
|
|
14470
15216
|
"data-worktree-state": decoration.state,
|
|
14471
15217
|
"aria-hidden": "true",
|
|
14472
15218
|
children: (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutlineRegular, {})
|
|
14473
|
-
}), (0, react_jsx_runtime$1.jsx)("span", {
|
|
15219
|
+
}), decoration.state !== "working" && (0, react_jsx_runtime$1.jsx)("span", {
|
|
14474
15220
|
className: "dsh-git-worktree-sidebar-badge",
|
|
14475
15221
|
"data-worktree-state": decoration.state,
|
|
14476
15222
|
"aria-hidden": "true",
|
|
@@ -14550,6 +15296,7 @@ const official$2 = ((require$1) => {
|
|
|
14550
15296
|
side: "bottom",
|
|
14551
15297
|
align: "end",
|
|
14552
15298
|
delayMs: 500,
|
|
15299
|
+
portal: true,
|
|
14553
15300
|
children: (0, react_jsx_runtime$1.jsx)("button", {
|
|
14554
15301
|
type: "button",
|
|
14555
15302
|
className: Rows_module_css_default.iconButton,
|
|
@@ -14709,6 +15456,7 @@ const official$2 = ((require$1) => {
|
|
|
14709
15456
|
t
|
|
14710
15457
|
}),
|
|
14711
15458
|
openDelayMs: 800,
|
|
15459
|
+
grouped: true,
|
|
14712
15460
|
disabled: menuOpen || drag?.active === true,
|
|
14713
15461
|
copyText: row.blank || row.title === "" ? void 0 : row.title,
|
|
14714
15462
|
copyLabel: t("copy"),
|
|
@@ -15137,22 +15885,46 @@ const official$2 = ((require$1) => {
|
|
|
15137
15885
|
const SEARCH_DEBOUNCE_MS = 250;
|
|
15138
15886
|
/** `session.search` wire bound, measured in JavaScript UTF-16 code units. */
|
|
15139
15887
|
const SEARCH_QUERY_MAX_CODE_UNITS = 500;
|
|
15140
|
-
/**
|
|
15141
|
-
const
|
|
15142
|
-
/**
|
|
15143
|
-
|
|
15144
|
-
|
|
15888
|
+
/** Non-blank Session rows visible per Workspace while no Session raises its watermark. */
|
|
15889
|
+
const SESSION_WATERMARK_BASE = 5;
|
|
15890
|
+
/** Highest watermark that attention-bearing Sessions raise automatically; Show more and search reveals may exceed it. */
|
|
15891
|
+
const SESSION_WATERMARK_AUTO_MAX = 50;
|
|
15892
|
+
/** Show the blank row plus the first `watermark` non-blank rows, in list order. */
|
|
15893
|
+
function watermarkRows(sessions, watermark) {
|
|
15894
|
+
let count = 0;
|
|
15145
15895
|
const rows = sessions.filter((session) => {
|
|
15146
|
-
if (session.blank
|
|
15147
|
-
|
|
15148
|
-
|
|
15149
|
-
return true;
|
|
15896
|
+
if (session.blank) return true;
|
|
15897
|
+
count += 1;
|
|
15898
|
+
return count <= watermark;
|
|
15150
15899
|
});
|
|
15151
15900
|
return {
|
|
15152
15901
|
rows,
|
|
15153
15902
|
hiddenCount: sessions.length - rows.length
|
|
15154
15903
|
};
|
|
15155
15904
|
}
|
|
15905
|
+
/**
|
|
15906
|
+
* Smallest watermark that covers every non-blank row within the automatic maximum that is running, has a running
|
|
15907
|
+
* child, awaits the user, carries an unread completion, or is current, and the reveal target at any position.
|
|
15908
|
+
*/
|
|
15909
|
+
function requiredWatermark(sessions, current, revealSessionId) {
|
|
15910
|
+
let index = 0;
|
|
15911
|
+
let required$1 = 0;
|
|
15912
|
+
for (const session of sessions) {
|
|
15913
|
+
if (session.blank) continue;
|
|
15914
|
+
index += 1;
|
|
15915
|
+
if (index <= SESSION_WATERMARK_AUTO_MAX && (session.running || session.runningSubagentCount > 0 || session.pendingInteraction !== void 0 || session.completed || session.id === current) || session.id === revealSessionId) required$1 = index;
|
|
15916
|
+
}
|
|
15917
|
+
return required$1;
|
|
15918
|
+
}
|
|
15919
|
+
/** Raise each listed group's watermark to its requirement; returns `marks` itself when nothing rises. */
|
|
15920
|
+
function raiseWatermarks(marks, required$1) {
|
|
15921
|
+
let raised = marks;
|
|
15922
|
+
for (const [key, watermark] of required$1) if (watermark > (raised[key] ?? SESSION_WATERMARK_BASE)) raised = {
|
|
15923
|
+
...raised,
|
|
15924
|
+
[key]: watermark
|
|
15925
|
+
};
|
|
15926
|
+
return raised;
|
|
15927
|
+
}
|
|
15156
15928
|
/** Keep controlled input and RPC payload inside the session.search wire contract. */
|
|
15157
15929
|
function sanitizeSearchQuery(value) {
|
|
15158
15930
|
const withoutNul = value.replaceAll("\0", "");
|
|
@@ -15333,13 +16105,14 @@ const official$2 = ((require$1) => {
|
|
|
15333
16105
|
]
|
|
15334
16106
|
});
|
|
15335
16107
|
}
|
|
15336
|
-
/** The scrolling session tree; unmounting drops the sessions subscription and
|
|
16108
|
+
/** The scrolling session tree; unmounting drops the sessions subscription and the session watermarks. */
|
|
15337
16109
|
function SessionTree({ list, useSessionStatus, startSession, open, workspaces, ungroupedSessionIds, rowState, onLeaveArchivedOnly, workspaceReady, animationResetKey, usePanelInfo, onRenameRequest, onDeleteRequest, onSessionRenameRequest, renderSlot, insertWorkspaceBefore, nestWorkspaces, groupExpansion, setGroupExpanded, setSessionOrder, home, t, revealSessionId, onSessionRevealed, shortcuts }) {
|
|
15338
16110
|
const panelActive = usePanelInfo((info) => info.activePanelId !== null);
|
|
15339
16111
|
const statuses = useSessionStatus((s) => s);
|
|
15340
16112
|
const current = panelActive ? void 0 : Object.values(list.byId).find((session) => (session.retainedBy.mainView ?? 0) > 0)?.id;
|
|
15341
16113
|
const revealGroup = revealSessionId === void 0 || !workspaceReady ? void 0 : owningGroupKey(workspaces, revealSessionId);
|
|
15342
|
-
const [
|
|
16114
|
+
const [storedWatermarks, setStoredWatermarks] = (0, react$1.useState)({});
|
|
16115
|
+
const [watermarkMotionKey, setWatermarkMotionKey] = (0, react$1.useState)(0);
|
|
15343
16116
|
const [drag, setDrag] = (0, react$1.useState)(null);
|
|
15344
16117
|
const sessionDropCommitted = (0, react$1.useRef)(false);
|
|
15345
16118
|
const [workspaceDrag, setWorkspaceDrag] = (0, react$1.useState)(null);
|
|
@@ -15397,20 +16170,24 @@ const official$2 = ((require$1) => {
|
|
|
15397
16170
|
revealGroup,
|
|
15398
16171
|
setGroupExpanded
|
|
15399
16172
|
]);
|
|
15400
|
-
(
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
15404
|
-
|
|
15405
|
-
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15411
|
-
|
|
15412
|
-
|
|
15413
|
-
|
|
16173
|
+
const baselines = new Map(groups.map((group) => [group.key, Math.max(SESSION_WATERMARK_BASE, requiredWatermark(group.sessions, current, group.key === revealGroup ? revealSessionId : void 0))]));
|
|
16174
|
+
const foldedKeys = new Set(groups.filter((group) => !group.expanded).map((group) => group.key));
|
|
16175
|
+
const underFoldedAncestor = (key) => {
|
|
16176
|
+
for (let owner = parents.get(key); owner !== void 0; owner = parents.get(owner)) if (foldedKeys.has(owner)) return true;
|
|
16177
|
+
return false;
|
|
16178
|
+
};
|
|
16179
|
+
const requiredWatermarks = new Map([...baselines].filter(([key]) => !underFoldedAncestor(key)));
|
|
16180
|
+
const sessionWatermarks = raiseWatermarks(storedWatermarks, requiredWatermarks);
|
|
16181
|
+
if (sessionWatermarks !== storedWatermarks) setStoredWatermarks((marks) => raiseWatermarks(marks, requiredWatermarks));
|
|
16182
|
+
const dropWatermarks = (drop) => {
|
|
16183
|
+
if (!Object.keys(storedWatermarks).some(drop)) return;
|
|
16184
|
+
setStoredWatermarks((marks) => Object.fromEntries(Object.entries(marks).filter(([key]) => !drop(key))));
|
|
16185
|
+
setWatermarkMotionKey((key) => key + 1);
|
|
16186
|
+
};
|
|
16187
|
+
const withinGroup = (key, root) => {
|
|
16188
|
+
for (let owner = key; owner !== void 0; owner = parents.get(owner)) if (owner === root) return true;
|
|
16189
|
+
return false;
|
|
16190
|
+
};
|
|
15414
16191
|
const now = Date.now();
|
|
15415
16192
|
const commitSessionDrag = (activeDrag, over) => {
|
|
15416
16193
|
if (sessionDropCommitted.current) return;
|
|
@@ -15421,7 +16198,7 @@ const official$2 = ((require$1) => {
|
|
|
15421
16198
|
if (over.id === activeDrag.sessionId) return;
|
|
15422
16199
|
const accountSessionIds = activeDrag.accountKey === "" ? ungroupedSessionIds : workspaces.find((workspace) => workspace.workspaceId === activeDrag.accountKey)?.sessionIds;
|
|
15423
16200
|
if (accountSessionIds === void 0) return;
|
|
15424
|
-
const renderedSessions =
|
|
16201
|
+
const renderedSessions = watermarkRows(group.sessions, sessionWatermarks[group.key] ?? SESSION_WATERMARK_BASE).rows;
|
|
15425
16202
|
const nextOrder = sessionDragOrder(accountSessionIds, renderedSessions, activeDrag, over);
|
|
15426
16203
|
if (nextOrder !== void 0) setSessionOrder(activeDrag.accountKey, nextOrder);
|
|
15427
16204
|
};
|
|
@@ -15461,8 +16238,9 @@ const official$2 = ((require$1) => {
|
|
|
15461
16238
|
const workspaceId = group.workspaceId;
|
|
15462
16239
|
const children = childrenByParent.get(group.key) ?? [];
|
|
15463
16240
|
const compatibleDrag = workspaceDrag !== null && parents.get(workspaceDrag.workspaceId) === parents.get(group.key);
|
|
15464
|
-
const
|
|
15465
|
-
const
|
|
16241
|
+
const watermark = sessionWatermarks[group.key] ?? SESSION_WATERMARK_BASE;
|
|
16242
|
+
const collapsed = watermarkRows(group.sessions, baselines.get(group.key) ?? SESSION_WATERMARK_BASE);
|
|
16243
|
+
const visible = watermarkRows(group.sessions, watermark);
|
|
15466
16244
|
const sessionsExpanded = visible.hiddenCount === 0;
|
|
15467
16245
|
rowKeys.push(`workspace:${group.key}`);
|
|
15468
16246
|
const childRows = group.expanded ? children.map((child) => renderGroup(child, depth + 1)) : [];
|
|
@@ -15534,10 +16312,7 @@ const official$2 = ((require$1) => {
|
|
|
15534
16312
|
home,
|
|
15535
16313
|
t,
|
|
15536
16314
|
onToggle: () => {
|
|
15537
|
-
if (group.expanded)
|
|
15538
|
-
...limits,
|
|
15539
|
-
[group.key]: COLLAPSED_SESSION_LIMIT
|
|
15540
|
-
}));
|
|
16315
|
+
if (group.expanded) dropWatermarks((key) => withinGroup(key, group.key));
|
|
15541
16316
|
setGroupExpanded(group.key, !group.expanded);
|
|
15542
16317
|
},
|
|
15543
16318
|
onCreate: () => {
|
|
@@ -15622,10 +16397,15 @@ const official$2 = ((require$1) => {
|
|
|
15622
16397
|
"data-row-key": `overflow:${group.key}`,
|
|
15623
16398
|
"aria-expanded": sessionsExpanded,
|
|
15624
16399
|
onClick: () => {
|
|
15625
|
-
|
|
15626
|
-
|
|
15627
|
-
|
|
16400
|
+
if (sessionsExpanded) {
|
|
16401
|
+
dropWatermarks((key) => key === group.key);
|
|
16402
|
+
return;
|
|
16403
|
+
}
|
|
16404
|
+
setStoredWatermarks((marks) => ({
|
|
16405
|
+
...marks,
|
|
16406
|
+
[group.key]: visible.hiddenCount <= SESSION_WATERMARK_BASE ? Infinity : watermark + SESSION_WATERMARK_BASE
|
|
15628
16407
|
}));
|
|
16408
|
+
setWatermarkMotionKey((key) => key + 1);
|
|
15629
16409
|
},
|
|
15630
16410
|
children: sessionsExpanded ? t("sessions.collapse") : t("sessions.expand", { n: visible.hiddenCount })
|
|
15631
16411
|
})
|
|
@@ -15633,7 +16413,7 @@ const official$2 = ((require$1) => {
|
|
|
15633
16413
|
}, group.key);
|
|
15634
16414
|
};
|
|
15635
16415
|
const groupRows = rootGroups.map((group) => renderGroup(group, 0));
|
|
15636
|
-
return (0, react_jsx_runtime$1.jsxs)(
|
|
16416
|
+
return (0, react_jsx_runtime$1.jsxs)(_deepseek_ai_dsh_client_ui_primitives.HoverCardGroup, {
|
|
15637
16417
|
className: clsx(WorkspaceBrowser_module_css_default.treeBody, WorkspaceBrowser_module_css_default.wide),
|
|
15638
16418
|
children: [
|
|
15639
16419
|
workspaceDropAtListStart && (0, react_jsx_runtime$1.jsx)("span", {
|
|
@@ -15645,7 +16425,7 @@ const official$2 = ((require$1) => {
|
|
|
15645
16425
|
label: t("section.sessions"),
|
|
15646
16426
|
rowKeys,
|
|
15647
16427
|
ready: list.phase === "ready" && workspaceReady && !nativeDragActive,
|
|
15648
|
-
resetKey: JSON.stringify([animationResetKey,
|
|
16428
|
+
resetKey: JSON.stringify([animationResetKey, watermarkMotionKey]),
|
|
15649
16429
|
children: [groups.length === 0 && (0, react_jsx_runtime$1.jsx)(EmptySessions, {
|
|
15650
16430
|
rowState,
|
|
15651
16431
|
onLeaveArchivedOnly,
|
|
@@ -15678,7 +16458,7 @@ const official$2 = ((require$1) => {
|
|
|
15678
16458
|
if (nextOrder !== void 0) setSessionOrder(FLAT_SESSION_ORDER_KEY, nextOrder);
|
|
15679
16459
|
};
|
|
15680
16460
|
const now = Date.now();
|
|
15681
|
-
return (0, react_jsx_runtime$1.jsxs)(
|
|
16461
|
+
return (0, react_jsx_runtime$1.jsxs)(_deepseek_ai_dsh_client_ui_primitives.HoverCardGroup, {
|
|
15682
16462
|
className: clsx(WorkspaceBrowser_module_css_default.treeBody, WorkspaceBrowser_module_css_default.wide),
|
|
15683
16463
|
children: [(0, react_jsx_runtime$1.jsxs)(AnimatedRows, {
|
|
15684
16464
|
className: clsx(WorkspaceBrowser_module_css_default.list, WorkspaceBrowser_module_css_default.flatList),
|
|
@@ -15811,7 +16591,7 @@ const official$2 = ((require$1) => {
|
|
|
15811
16591
|
* @param props - composed slot props (shell owner share + store + injected actions).
|
|
15812
16592
|
* @returns the region element tree.
|
|
15813
16593
|
*/
|
|
15814
|
-
function WorkspaceBrowser({ wide, usePanelInfo, expandSidebar, useSessions, useSessionStatus, useWorkspaces, useStore, actions, startSession, open, requestSessionRename, notifyArchivedNotOpenable, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, unarchiveSession, createWorkspace, searchSessions, searchResultLimit, useDirectoryFlow, useHostInfo, useShortcuts, useWorkspaceShortcuts, requestSearch, requestAddWorkspace, closeAddWorkspace, setDirectoryBusy,
|
|
16594
|
+
function WorkspaceBrowser({ wide, usePanelInfo, expandSidebar, useSessions, useSessionStatus, useWorkspaces, useStore, actions, startSession, open, requestSessionRename, notifyArchivedNotOpenable, renameWorkspace, deleteWorkspace, insertWorkspaceBefore, unarchiveSession, createWorkspace, searchSessions, searchResultLimit, useDirectoryFlow, useHostInfo, useShortcuts, useWorkspaceShortcuts, requestSearch, requestAddWorkspace, closeAddWorkspace, setDirectoryBusy, renderSlot, t }) {
|
|
15815
16595
|
const home = useHostInfo((info) => info.home);
|
|
15816
16596
|
const shortcuts = useShortcuts((rows) => rows);
|
|
15817
16597
|
const searchShortcut = shortcuts.find((row) => row.id === "session.search");
|
|
@@ -16240,7 +17020,7 @@ const official$2 = ((require$1) => {
|
|
|
16240
17020
|
side: "right",
|
|
16241
17021
|
onPick: (workspaceId) => {
|
|
16242
17022
|
closeAddWorkspace();
|
|
16243
|
-
startSession(workspaceId);
|
|
17023
|
+
startSession(workspaceId, { clearPreviousDraft: false });
|
|
16244
17024
|
},
|
|
16245
17025
|
onClose: () => {
|
|
16246
17026
|
closeAddWorkspace();
|
|
@@ -16419,11 +17199,7 @@ const official$2 = ((require$1) => {
|
|
|
16419
17199
|
role: "alert",
|
|
16420
17200
|
children: deleteError
|
|
16421
17201
|
})]
|
|
16422
|
-
})
|
|
16423
|
-
shortcutState.forkError !== null && (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
16424
|
-
text: t(shortcutState.forkError.reason === "unavailable" ? "shortcut.noCompletedTurn" : "shortcut.forkFailed"),
|
|
16425
|
-
onDone: dismissForkError
|
|
16426
|
-
}, shortcutState.forkError.seq)
|
|
17202
|
+
})
|
|
16427
17203
|
]
|
|
16428
17204
|
});
|
|
16429
17205
|
}
|
|
@@ -16466,6 +17242,7 @@ const official$2 = ((require$1) => {
|
|
|
16466
17242
|
side: "bottom",
|
|
16467
17243
|
align: "end",
|
|
16468
17244
|
delayMs: 500,
|
|
17245
|
+
portal: true,
|
|
16469
17246
|
children: (0, react_jsx_runtime$1.jsx)("button", {
|
|
16470
17247
|
type: "button",
|
|
16471
17248
|
className: Rows_module_css_default.iconButton,
|
|
@@ -16607,14 +17384,17 @@ const official$2 = ((require$1) => {
|
|
|
16607
17384
|
/** The fork action: one `sidebar.workspaces.session.menu.item` row. */
|
|
16608
17385
|
/**
|
|
16609
17386
|
* Menu row (order 300): fork at the Session's last completed turn; the child
|
|
16610
|
-
* arrives through the Host list beside its source.
|
|
16611
|
-
*
|
|
16612
|
-
* @
|
|
17387
|
+
* arrives through the Host list beside its source. Absent when the access
|
|
17388
|
+
* snapshot excludes `session/fork` for this Session.
|
|
17389
|
+
* @param props - owner share, menu open state, access Hook, and the fork share.
|
|
17390
|
+
* @returns the row, or nothing when the caller may not fork this Session.
|
|
16613
17391
|
*/
|
|
16614
|
-
function ForkSessionMenuItem({ sessionId, useMenuOpenState, useShortcuts, forkSession, t }) {
|
|
17392
|
+
function ForkSessionMenuItem({ sessionId, useMenuOpenState, useShortcuts, useSessionAccess, forkSession, t }) {
|
|
16615
17393
|
const [, setMenuOpen] = useMenuOpenState();
|
|
17394
|
+
const shortcut = useShortcuts((rows) => rows.find((row) => row.id === "session.fork"));
|
|
17395
|
+
if (!useSessionAccess(sessionId, "session/fork")) return null;
|
|
16616
17396
|
return (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.MenuItemButton, {
|
|
16617
|
-
shortcut
|
|
17397
|
+
shortcut,
|
|
16618
17398
|
icon: (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutlineRegular, {}),
|
|
16619
17399
|
onSelect: () => {
|
|
16620
17400
|
setMenuOpen(false);
|
|
@@ -16671,6 +17451,7 @@ const official$2 = ((require$1) => {
|
|
|
16671
17451
|
side: "bottom",
|
|
16672
17452
|
align: "end",
|
|
16673
17453
|
delayMs: 500,
|
|
17454
|
+
portal: true,
|
|
16674
17455
|
children: (0, react_jsx_runtime$1.jsx)("button", {
|
|
16675
17456
|
type: "button",
|
|
16676
17457
|
className: Rows_module_css_default.iconButton,
|
|
@@ -16797,72 +17578,232 @@ const official$2 = ((require$1) => {
|
|
|
16797
17578
|
});
|
|
16798
17579
|
}
|
|
16799
17580
|
/**
|
|
16800
|
-
*
|
|
16801
|
-
*
|
|
17581
|
+
* Dispatch the current notice without interpreting its business payload.
|
|
17582
|
+
* @param props - Current notice, dismissal, and the declared keyed renderer.
|
|
17583
|
+
* @returns The selected notice presentation, or nothing.
|
|
16802
17584
|
*/
|
|
17585
|
+
function RowActionToast({ useToast, dismissToast, renderSlot }) {
|
|
17586
|
+
const notice = useToast((current) => current);
|
|
17587
|
+
if (notice === null) return null;
|
|
17588
|
+
return renderSlot("workspace.toast", {
|
|
17589
|
+
...notice,
|
|
17590
|
+
dismissToast
|
|
17591
|
+
}, { entryKey: notice.kind });
|
|
17592
|
+
}
|
|
17593
|
+
/** One presentation Factory and the adapters for keyed Workspace notices. */
|
|
16803
17594
|
/**
|
|
16804
|
-
*
|
|
16805
|
-
*
|
|
16806
|
-
*
|
|
17595
|
+
* Render one notice using the shared Factory.
|
|
17596
|
+
* @param props - Keyed payload, injected display mapping, locale, and Factory renderer.
|
|
17597
|
+
* @returns The shared Toast occurrence.
|
|
16807
17598
|
*/
|
|
16808
|
-
|
|
17599
|
+
function ToastEntry(props) {
|
|
17600
|
+
const { dismissToast, display, t, renderFactorySlot, seq } = props;
|
|
17601
|
+
return renderFactorySlot("workspace.toast.content", {
|
|
17602
|
+
...display(props, t, dismissToast),
|
|
17603
|
+
seq,
|
|
17604
|
+
onDone: dismissToast
|
|
17605
|
+
});
|
|
17606
|
+
}
|
|
16809
17607
|
/**
|
|
16810
|
-
*
|
|
16811
|
-
*
|
|
16812
|
-
*
|
|
16813
|
-
* reason on the same hold, or a plain warning for a failed pin, an archived
|
|
16814
|
-
* row that was clicked, or default Workspace creation.
|
|
16815
|
-
* @param props - the notice hook, the shared viewing store, the notice dismissal, the two archived-notice actions, and the locale seat.
|
|
16816
|
-
* @returns the notice on display, or null.
|
|
17608
|
+
* Keep the archive filter action reactive without subscribing unrelated notices.
|
|
17609
|
+
* @param props - Archive notice, display mapping, and the existing viewing store.
|
|
17610
|
+
* @returns The shared Toast occurrence with its current actions.
|
|
16817
17611
|
*/
|
|
16818
|
-
function
|
|
16819
|
-
const
|
|
16820
|
-
const
|
|
16821
|
-
|
|
16822
|
-
|
|
16823
|
-
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
tone: "success",
|
|
16827
|
-
holdMs: LONG_TOAST_HOLD_MS,
|
|
16828
|
-
actions: [{
|
|
16829
|
-
label: t("toast.archivedUndo"),
|
|
16830
|
-
onClick: () => {
|
|
16831
|
-
dismissToast();
|
|
16832
|
-
undoArchive(sessionId);
|
|
16833
|
-
}
|
|
16834
|
-
}, ...archivedRowsVisible ? [] : [{
|
|
16835
|
-
prefix: t("toast.archivedOr"),
|
|
16836
|
-
label: t("toast.archivedFilter"),
|
|
16837
|
-
onClick: () => {
|
|
16838
|
-
dismissToast();
|
|
16839
|
-
showArchived();
|
|
16840
|
-
}
|
|
16841
|
-
}]],
|
|
16842
|
-
onDone: dismissToast
|
|
16843
|
-
}, `toast-${String(toast.seq)}`);
|
|
16844
|
-
}
|
|
16845
|
-
if (toast.kind === "createFailed") return (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
16846
|
-
text: t("toast.createFailed", { message: toast.message }),
|
|
16847
|
-
icon: (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}),
|
|
16848
|
-
holdMs: LONG_TOAST_HOLD_MS,
|
|
17612
|
+
function ArchiveToastEntry(props) {
|
|
17613
|
+
const { dismissToast, display, filterAction, useStore, t, renderFactorySlot, seq } = props;
|
|
17614
|
+
const archivedVisible = useStore((state) => (state.archivedFilter ?? "default") !== "default");
|
|
17615
|
+
const fields = display(props, t, dismissToast);
|
|
17616
|
+
return renderFactorySlot("workspace.toast.content", {
|
|
17617
|
+
...fields,
|
|
17618
|
+
actions: [...fields.actions ?? [], ...archivedVisible ? [] : [filterAction(t, dismissToast)]],
|
|
17619
|
+
seq,
|
|
16849
17620
|
onDone: dismissToast
|
|
16850
|
-
}
|
|
17621
|
+
});
|
|
17622
|
+
}
|
|
17623
|
+
/**
|
|
17624
|
+
* Present plain display data with the shared primitive's timing and portal.
|
|
17625
|
+
* @param props - Localized display fields, display identity, and dismissal.
|
|
17626
|
+
* @returns One Toast, remounted only for a new display identity.
|
|
17627
|
+
*/
|
|
17628
|
+
function WorkspaceToast({ seq, text, tone, holdMs, actions, onDone }) {
|
|
16851
17629
|
return (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
|
|
16852
|
-
text
|
|
16853
|
-
|
|
16854
|
-
|
|
16855
|
-
|
|
17630
|
+
text,
|
|
17631
|
+
onDone,
|
|
17632
|
+
...tone === "success" ? { tone: "success" } : {},
|
|
17633
|
+
...tone === "warning" ? { icon: (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconWarningOutlineRegular, {}) } : {},
|
|
17634
|
+
...holdMs === void 0 ? {} : { holdMs },
|
|
17635
|
+
...actions === void 0 ? {} : { actions }
|
|
17636
|
+
}, seq);
|
|
17637
|
+
}
|
|
17638
|
+
/** Register notice presentations with their business-owned display fields and actions.
|
|
17639
|
+
* @param ctx - Workspace plugin context.
|
|
17640
|
+
* @param viewStore - Viewing store, read only by archive notices.
|
|
17641
|
+
* @param actions - Archive and source-opening callbacks.
|
|
17642
|
+
*/
|
|
17643
|
+
function registerToasts(ctx, viewStore, actions) {
|
|
17644
|
+
const archiveFilterAction = (t, dismiss) => ({
|
|
17645
|
+
prefix: t("toast.archivedOr"),
|
|
17646
|
+
label: t("toast.archivedFilter"),
|
|
17647
|
+
onClick: () => {
|
|
17648
|
+
dismiss();
|
|
17649
|
+
actions.showArchived();
|
|
17650
|
+
}
|
|
17651
|
+
});
|
|
17652
|
+
ctx.slots.registerFactory({
|
|
17653
|
+
name: "workspace.toast.content",
|
|
17654
|
+
scope: "root"
|
|
17655
|
+
}, WorkspaceToast);
|
|
17656
|
+
ctx.slots.inject("workspace.toast", function* () {
|
|
17657
|
+
yield ctx.slots.register({
|
|
17658
|
+
name: "workspace.toast",
|
|
17659
|
+
key: "sessionIdCopied",
|
|
17660
|
+
locale: "workspace",
|
|
17661
|
+
inject: () => ({ display: (_notice, t) => ({
|
|
17662
|
+
text: t("toast.sessionIdCopied"),
|
|
17663
|
+
tone: "success"
|
|
17664
|
+
}) })
|
|
17665
|
+
}, ToastEntry);
|
|
17666
|
+
yield ctx.slots.register({
|
|
17667
|
+
name: "workspace.toast",
|
|
17668
|
+
key: "sessionIdCopyFailed",
|
|
17669
|
+
locale: "workspace",
|
|
17670
|
+
inject: () => ({ display: (_notice, t) => ({
|
|
17671
|
+
text: t("toast.sessionIdCopyFailed"),
|
|
17672
|
+
tone: "warning"
|
|
17673
|
+
}) })
|
|
17674
|
+
}, ToastEntry);
|
|
17675
|
+
yield ctx.slots.register({
|
|
17676
|
+
name: "workspace.toast",
|
|
17677
|
+
key: "pinFailed",
|
|
17678
|
+
locale: "workspace",
|
|
17679
|
+
inject: () => ({ display: (_notice, t) => ({
|
|
17680
|
+
text: t("toast.pinFailed"),
|
|
17681
|
+
tone: "warning"
|
|
17682
|
+
}) })
|
|
17683
|
+
}, ToastEntry);
|
|
17684
|
+
yield ctx.slots.register({
|
|
17685
|
+
name: "workspace.toast",
|
|
17686
|
+
key: "unpinFailed",
|
|
17687
|
+
locale: "workspace",
|
|
17688
|
+
inject: () => ({ display: (_notice, t) => ({
|
|
17689
|
+
text: t("toast.unpinFailed"),
|
|
17690
|
+
tone: "warning"
|
|
17691
|
+
}) })
|
|
17692
|
+
}, ToastEntry);
|
|
17693
|
+
yield ctx.slots.register({
|
|
17694
|
+
name: "workspace.toast",
|
|
17695
|
+
key: "archivedNotOpenable",
|
|
17696
|
+
locale: "workspace",
|
|
17697
|
+
inject: () => ({ display: (_notice, t) => ({
|
|
17698
|
+
text: t("toast.archivedNotOpenable"),
|
|
17699
|
+
tone: "warning"
|
|
17700
|
+
}) })
|
|
17701
|
+
}, ToastEntry);
|
|
17702
|
+
yield ctx.slots.register({
|
|
17703
|
+
name: "workspace.toast",
|
|
17704
|
+
key: "defaultWorkspaceFailed",
|
|
17705
|
+
locale: "workspace",
|
|
17706
|
+
inject: () => ({ display: (_notice, t) => ({
|
|
17707
|
+
text: t("defaultWorkspace.failed"),
|
|
17708
|
+
tone: "warning"
|
|
17709
|
+
}) })
|
|
17710
|
+
}, ToastEntry);
|
|
17711
|
+
yield ctx.slots.register({
|
|
17712
|
+
name: "workspace.toast",
|
|
17713
|
+
key: "shortcutForkFailed",
|
|
17714
|
+
locale: "workspace",
|
|
17715
|
+
inject: () => ({ display: (notice, t) => ({
|
|
17716
|
+
text: t(notice.reason === "unavailable" ? "shortcut.noCompletedTurn" : "shortcut.forkFailed"),
|
|
17717
|
+
tone: "plain"
|
|
17718
|
+
}) })
|
|
17719
|
+
}, ToastEntry);
|
|
17720
|
+
yield ctx.slots.register({
|
|
17721
|
+
name: "workspace.toast",
|
|
17722
|
+
key: "createFailed",
|
|
17723
|
+
locale: "workspace",
|
|
17724
|
+
inject: () => ({ display: (notice, t) => ({
|
|
17725
|
+
text: t("toast.createFailed", { message: notice.message }),
|
|
17726
|
+
tone: "warning",
|
|
17727
|
+
holdMs: 6e3
|
|
17728
|
+
}) })
|
|
17729
|
+
}, ToastEntry);
|
|
17730
|
+
yield ctx.slots.register({
|
|
17731
|
+
name: "workspace.toast",
|
|
17732
|
+
key: "forkRequiresOpen",
|
|
17733
|
+
locale: "workspace",
|
|
17734
|
+
inject: () => ({ display: (notice, t, dismiss) => ({
|
|
17735
|
+
text: t("toast.forkRequiresOpen"),
|
|
17736
|
+
tone: "warning",
|
|
17737
|
+
holdMs: 6e3,
|
|
17738
|
+
actions: [{
|
|
17739
|
+
label: t("toast.openForkSource"),
|
|
17740
|
+
onClick: () => {
|
|
17741
|
+
dismiss();
|
|
17742
|
+
actions.openForkSource(notice.sessionId);
|
|
17743
|
+
}
|
|
17744
|
+
}]
|
|
17745
|
+
}) })
|
|
17746
|
+
}, ToastEntry);
|
|
17747
|
+
yield ctx.slots.register({
|
|
17748
|
+
name: "workspace.toast",
|
|
17749
|
+
key: "archived",
|
|
17750
|
+
locale: "workspace",
|
|
17751
|
+
store: viewStore,
|
|
17752
|
+
inject: () => ({
|
|
17753
|
+
display: (notice, t, dismiss) => ({
|
|
17754
|
+
text: t("toast.archived"),
|
|
17755
|
+
tone: "success",
|
|
17756
|
+
holdMs: 6e3,
|
|
17757
|
+
actions: [{
|
|
17758
|
+
label: t("toast.archivedUndo"),
|
|
17759
|
+
onClick: () => {
|
|
17760
|
+
dismiss();
|
|
17761
|
+
actions.undoArchive(notice.sessionId);
|
|
17762
|
+
}
|
|
17763
|
+
}]
|
|
17764
|
+
}),
|
|
17765
|
+
filterAction: archiveFilterAction
|
|
17766
|
+
})
|
|
17767
|
+
}, ArchiveToastEntry);
|
|
17768
|
+
yield ctx.slots.register({
|
|
17769
|
+
name: "workspace.toast",
|
|
17770
|
+
key: "stoppedAndArchived",
|
|
17771
|
+
locale: "workspace",
|
|
17772
|
+
store: viewStore,
|
|
17773
|
+
inject: () => ({
|
|
17774
|
+
display: (notice, t, dismiss) => ({
|
|
17775
|
+
text: t("toast.stoppedAndArchived"),
|
|
17776
|
+
tone: "success",
|
|
17777
|
+
holdMs: 6e3,
|
|
17778
|
+
actions: [{
|
|
17779
|
+
label: t("toast.archivedUndo"),
|
|
17780
|
+
onClick: () => {
|
|
17781
|
+
dismiss();
|
|
17782
|
+
actions.undoArchive(notice.sessionId);
|
|
17783
|
+
}
|
|
17784
|
+
}]
|
|
17785
|
+
}),
|
|
17786
|
+
filterAction: archiveFilterAction
|
|
17787
|
+
})
|
|
17788
|
+
}, ArchiveToastEntry);
|
|
17789
|
+
});
|
|
16856
17790
|
}
|
|
16857
|
-
/**
|
|
16858
|
-
|
|
16859
|
-
|
|
16860
|
-
|
|
16861
|
-
|
|
16862
|
-
|
|
16863
|
-
|
|
16864
|
-
|
|
16865
|
-
|
|
17791
|
+
/** Copy the row's Session ID without opening its history. */
|
|
17792
|
+
/**
|
|
17793
|
+
* Copy the complete ID after dismissing the row menu.
|
|
17794
|
+
* @param props - Row identity, menu dismissal, clipboard action, and locale.
|
|
17795
|
+
* @returns The final built-in menu item.
|
|
17796
|
+
*/
|
|
17797
|
+
function SessionIdMenuItem({ sessionId, useMenuOpenState, copySessionId, t }) {
|
|
17798
|
+
const [, setMenuOpen] = useMenuOpenState();
|
|
17799
|
+
return (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.MenuItemButton, {
|
|
17800
|
+
icon: (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutlineRegular, {}),
|
|
17801
|
+
onSelect: () => {
|
|
17802
|
+
setMenuOpen(false);
|
|
17803
|
+
copySessionId(sessionId);
|
|
17804
|
+
},
|
|
17805
|
+
children: t("menu.sessionId")
|
|
17806
|
+
});
|
|
16866
17807
|
}
|
|
16867
17808
|
/**
|
|
16868
17809
|
* `workspace` namespace dictionaries: the browsing region (section header,
|
|
@@ -16880,6 +17821,8 @@ const official$2 = ((require$1) => {
|
|
|
16880
17821
|
"dshGitWorktree.state.finalized": "已完成",
|
|
16881
17822
|
"dshGitWorktree.state.discarded": "已放弃",
|
|
16882
17823
|
"defaultWorkspace.failed": "无法创建默认工作区,请通过“选择工作区”选择文件夹",
|
|
17824
|
+
"draft.workspaceRequired": "请先选择工作区",
|
|
17825
|
+
"draft.initializationFailed": "暂时无法填入草稿,请稍后重试",
|
|
16883
17826
|
"group.ungrouped": "未分组",
|
|
16884
17827
|
"session.new": "新会话",
|
|
16885
17828
|
"session.untitled": "未命名",
|
|
@@ -16934,6 +17877,9 @@ const official$2 = ((require$1) => {
|
|
|
16934
17877
|
"menu.unarchiveSession": "取消归档",
|
|
16935
17878
|
"menu.pinSession": "置顶会话",
|
|
16936
17879
|
"menu.unpinSession": "取消置顶",
|
|
17880
|
+
"menu.sessionId": "复制 Session ID",
|
|
17881
|
+
"toast.sessionIdCopied": "Session ID 已复制",
|
|
17882
|
+
"toast.sessionIdCopyFailed": "复制失败,请重试",
|
|
16937
17883
|
"row.archived": "已归档",
|
|
16938
17884
|
"row.pinned": "已置顶",
|
|
16939
17885
|
"toast.archivedNotOpenable": "已归档对话暂时无法查看,请取消归档后查看",
|
|
@@ -16960,6 +17906,8 @@ const official$2 = ((require$1) => {
|
|
|
16960
17906
|
"toast.pinFailed": "置顶失败,请稍后重试",
|
|
16961
17907
|
"toast.unpinFailed": "取消置顶失败,请稍后重试",
|
|
16962
17908
|
"toast.createFailed": "新建会话失败:{message}",
|
|
17909
|
+
"toast.forkRequiresOpen": "请先打开原会话完成迁移,再创建分支",
|
|
17910
|
+
"toast.openForkSource": "打开原会话",
|
|
16963
17911
|
"sessions.count.one": "{n} 个会话",
|
|
16964
17912
|
"sessions.count.other": "{n} 个会话",
|
|
16965
17913
|
"actions.workspace.aria": "工作区“{name}”的操作",
|
|
@@ -17003,6 +17951,8 @@ const official$2 = ((require$1) => {
|
|
|
17003
17951
|
"dshGitWorktree.state.finalized": "Done",
|
|
17004
17952
|
"dshGitWorktree.state.discarded": "Discarded",
|
|
17005
17953
|
"defaultWorkspace.failed": "Unable to create default workspace. Use Choose workspace to select a folder.",
|
|
17954
|
+
"draft.workspaceRequired": "Choose a workspace first.",
|
|
17955
|
+
"draft.initializationFailed": "Could not fill the draft. Please try again shortly.",
|
|
17006
17956
|
"group.ungrouped": "Ungrouped",
|
|
17007
17957
|
"session.new": "New Session",
|
|
17008
17958
|
"session.untitled": "Untitled",
|
|
@@ -17057,6 +18007,9 @@ const official$2 = ((require$1) => {
|
|
|
17057
18007
|
"menu.unarchiveSession": "Unarchive session",
|
|
17058
18008
|
"menu.pinSession": "Pin session",
|
|
17059
18009
|
"menu.unpinSession": "Unpin session",
|
|
18010
|
+
"menu.sessionId": "Copy Session ID",
|
|
18011
|
+
"toast.sessionIdCopied": "Session ID copied",
|
|
18012
|
+
"toast.sessionIdCopyFailed": "Copy failed. Try again.",
|
|
17060
18013
|
"row.archived": "Archived",
|
|
17061
18014
|
"row.pinned": "Pinned",
|
|
17062
18015
|
"toast.archivedNotOpenable": "Archived sessions cannot be opened. Unarchive it to view.",
|
|
@@ -17083,6 +18036,8 @@ const official$2 = ((require$1) => {
|
|
|
17083
18036
|
"toast.pinFailed": "Pin failed. Try again later.",
|
|
17084
18037
|
"toast.unpinFailed": "Unpin failed. Try again later.",
|
|
17085
18038
|
"toast.createFailed": "New session failed: {message}",
|
|
18039
|
+
"toast.forkRequiresOpen": "Open the original session to complete migration before creating a branch.",
|
|
18040
|
+
"toast.openForkSource": "Open original session",
|
|
17086
18041
|
"sessions.count.one": "{n} session",
|
|
17087
18042
|
"sessions.count.other": "{n} sessions",
|
|
17088
18043
|
"actions.workspace.aria": "Workspace actions for {name}",
|
|
@@ -17133,7 +18088,8 @@ const official$2 = ((require$1) => {
|
|
|
17133
18088
|
"remote",
|
|
17134
18089
|
"remote.directoryPicker",
|
|
17135
18090
|
"layout",
|
|
17136
|
-
"shortcuts"
|
|
18091
|
+
"shortcuts",
|
|
18092
|
+
"remoteAccess"
|
|
17137
18093
|
];
|
|
17138
18094
|
/**
|
|
17139
18095
|
* Register the browser and picker once their slot declarations are on the
|
|
@@ -17159,7 +18115,10 @@ const official$2 = ((require$1) => {
|
|
|
17159
18115
|
});
|
|
17160
18116
|
};
|
|
17161
18117
|
const uiWorkspace = new UiWorkspaceService(ctx, ctx.remote.directoryPicker, workspaces, sessions, viewInstance.actions, notify);
|
|
17162
|
-
ctx.slots.provideRoot({
|
|
18118
|
+
ctx.slots.provideRoot({
|
|
18119
|
+
hooks: { workspaces: workspaces.list },
|
|
18120
|
+
keyedHooks: { workspaceAccess: (workspaceId, action) => action === void 0 ? void 0 : ctx.remoteAccess.source("workspace", workspaceId, action) }
|
|
18121
|
+
});
|
|
17163
18122
|
ctx.effect(() => ctx.locale.register(NS, {
|
|
17164
18123
|
zh,
|
|
17165
18124
|
en
|
|
@@ -17237,7 +18196,12 @@ const official$2 = ((require$1) => {
|
|
|
17237
18196
|
},
|
|
17238
18197
|
unarchiveSession
|
|
17239
18198
|
});
|
|
17240
|
-
installWorkspaceShortcuts(ctx, uiWorkspace, shortcutControls, archiveInjected().archiveSession)
|
|
18199
|
+
installWorkspaceShortcuts(ctx, uiWorkspace, shortcutControls, archiveInjected().archiveSession, (reason) => {
|
|
18200
|
+
notify({
|
|
18201
|
+
kind: "shortcutForkFailed",
|
|
18202
|
+
reason
|
|
18203
|
+
});
|
|
18204
|
+
});
|
|
17241
18205
|
const archiveConfirmInjected = () => ({
|
|
17242
18206
|
hooks: { archiveRequest },
|
|
17243
18207
|
settleSessionArchive: () => {
|
|
@@ -17258,7 +18222,15 @@ const official$2 = ((require$1) => {
|
|
|
17258
18222
|
parent_session_id: sessionId,
|
|
17259
18223
|
click_position: "sidebar"
|
|
17260
18224
|
});
|
|
17261
|
-
}).catch(() => {
|
|
18225
|
+
}, { allowMigration: false }).catch((error) => {
|
|
18226
|
+
if (error instanceof Error && error.name === "SessionForkError" && error.rpcError.code === "session/migration-required") notify({
|
|
18227
|
+
kind: "forkRequiresOpen",
|
|
18228
|
+
sessionId
|
|
18229
|
+
});
|
|
18230
|
+
});
|
|
18231
|
+
} });
|
|
18232
|
+
const sessionIdInjected = () => ({ copySessionId: async (sessionId) => {
|
|
18233
|
+
notify({ kind: await (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(sessionId) ? "sessionIdCopied" : "sessionIdCopyFailed" });
|
|
17262
18234
|
} });
|
|
17263
18235
|
const renameInjected = () => ({ requestSessionRename });
|
|
17264
18236
|
const renameDialogInjected = () => ({
|
|
@@ -17266,19 +18238,28 @@ const official$2 = ((require$1) => {
|
|
|
17266
18238
|
settleSessionRename: shortcutControls.closeRename,
|
|
17267
18239
|
renameSession
|
|
17268
18240
|
});
|
|
18241
|
+
registerToasts(ctx, viewStore, {
|
|
18242
|
+
undoArchive: unarchiveSession,
|
|
18243
|
+
showArchived: () => {
|
|
18244
|
+
viewInstance.actions.setArchivedFilter("show");
|
|
18245
|
+
},
|
|
18246
|
+
openForkSource: (sessionId) => {
|
|
18247
|
+
if (workspaces.list.getSnapshot().archivedSessionIds.includes(sessionId)) {
|
|
18248
|
+
notify({ kind: "archivedNotOpenable" });
|
|
18249
|
+
return;
|
|
18250
|
+
}
|
|
18251
|
+
openSession(sessionId);
|
|
18252
|
+
}
|
|
18253
|
+
});
|
|
17269
18254
|
const rowToastInjected = () => ({
|
|
17270
18255
|
hooks: { toast: rowToast },
|
|
17271
18256
|
dismissToast: () => {
|
|
17272
18257
|
rowToast.set(null);
|
|
17273
|
-
},
|
|
17274
|
-
undoArchive: unarchiveSession,
|
|
17275
|
-
showArchived: () => {
|
|
17276
|
-
viewInstance.actions.setArchivedFilter("show");
|
|
17277
18258
|
}
|
|
17278
18259
|
});
|
|
17279
18260
|
const browserInjected = () => ({
|
|
17280
|
-
startSession: (workspaceId) => {
|
|
17281
|
-
uiWorkspace.startSession(workspaceId);
|
|
18261
|
+
startSession: (workspaceId, options) => {
|
|
18262
|
+
uiWorkspace.startSession(workspaceId, options);
|
|
17282
18263
|
},
|
|
17283
18264
|
open: openSession,
|
|
17284
18265
|
searchSessions,
|
|
@@ -17304,7 +18285,6 @@ const official$2 = ((require$1) => {
|
|
|
17304
18285
|
requestAddWorkspace: shortcutControls.add,
|
|
17305
18286
|
closeAddWorkspace: shortcutControls.closeAdd,
|
|
17306
18287
|
setDirectoryBusy: shortcutControls.directoryBusy,
|
|
17307
|
-
dismissForkError: shortcutControls.dismissForkError,
|
|
17308
18288
|
hooks: {
|
|
17309
18289
|
directoryFlow: browserFlowSource,
|
|
17310
18290
|
hostInfo,
|
|
@@ -17377,6 +18357,13 @@ const official$2 = ((require$1) => {
|
|
|
17377
18357
|
locale: NS,
|
|
17378
18358
|
inject: archiveInjected
|
|
17379
18359
|
}, ArchiveSessionMenuItem);
|
|
18360
|
+
yield ctx.slots.register({
|
|
18361
|
+
name: "sidebar.workspaces.session.menu.item",
|
|
18362
|
+
id: "session-id",
|
|
18363
|
+
order: 450,
|
|
18364
|
+
locale: NS,
|
|
18365
|
+
inject: sessionIdInjected
|
|
18366
|
+
}, SessionIdMenuItem);
|
|
17380
18367
|
});
|
|
17381
18368
|
ctx.slots.inject("sidebar.workspaces.session.row.action", function* () {
|
|
17382
18369
|
yield ctx.slots.register({
|
|
@@ -17410,9 +18397,11 @@ const official$2 = ((require$1) => {
|
|
|
17410
18397
|
yield ctx.slots.register({
|
|
17411
18398
|
name: "shell.overlay",
|
|
17412
18399
|
id: "workspace.row-toast",
|
|
17413
|
-
|
|
17414
|
-
|
|
17415
|
-
|
|
18400
|
+
inject: rowToastInjected,
|
|
18401
|
+
children: { "workspace.toast": {
|
|
18402
|
+
kind: "keyed",
|
|
18403
|
+
scope: "root"
|
|
18404
|
+
} }
|
|
17416
18405
|
}, RowActionToast);
|
|
17417
18406
|
});
|
|
17418
18407
|
ctx.slots.inject("conversation.hero.workspace", () => ctx.slots.register({
|
|
@@ -17573,6 +18562,12 @@ function projectManagedWorkspaceSidebar(input, t = defaultClientTranslator) {
|
|
|
17573
18562
|
//#endregion
|
|
17574
18563
|
//#region src/client/workspace-sidebar/index.tsx
|
|
17575
18564
|
const EMPTY_TOPOLOGY = { projects: [] };
|
|
18565
|
+
const OWNER_SAFE_SESSION_ACTIONS = new Set([
|
|
18566
|
+
"pin",
|
|
18567
|
+
"rename",
|
|
18568
|
+
"archive",
|
|
18569
|
+
"session-id"
|
|
18570
|
+
]);
|
|
17576
18571
|
/**
|
|
17577
18572
|
* Preserve the complete official Workspace Browser and change only its data
|
|
17578
18573
|
* projection plus mutations that are unsafe for one-to-one Managed owners.
|
|
@@ -17732,7 +18727,7 @@ function officialContextProxy(ctx, adapter) {
|
|
|
17732
18727
|
};
|
|
17733
18728
|
const proxySlots = new Proxy(ctx.slots, { get(target, key, receiver) {
|
|
17734
18729
|
if (key === "register") return (descriptor$1, component) => {
|
|
17735
|
-
if ((descriptor$1.name === "sidebar.workspaces.session.menu.item" || descriptor$1.name === "sidebar.workspaces.session.row.action") && descriptor$1.id
|
|
18730
|
+
if ((descriptor$1.name === "sidebar.workspaces.session.menu.item" || descriptor$1.name === "sidebar.workspaces.session.row.action") && !OWNER_SAFE_SESSION_ACTIONS.has(descriptor$1.id)) {
|
|
17736
18731
|
const Action = component;
|
|
17737
18732
|
const GuardedAction = (props) => typeof props.sessionId === "string" && !guard.blockSession(props.sessionId) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Action, { ...props }) : null;
|
|
17738
18733
|
return target.register(descriptor$1, GuardedAction);
|
|
@@ -18541,6 +19536,7 @@ const official$1 = ((require$1) => {
|
|
|
18541
19536
|
*/
|
|
18542
19537
|
constructor(ctx, directoryPicker, workspaces, sessions, view, notify) {
|
|
18543
19538
|
super(ctx, "uiWorkspace");
|
|
19539
|
+
this.managedWorktreeGuard = ctx.get("__dshGitWorktreeManagedGuard");
|
|
18544
19540
|
this.directoryPicker = directoryPicker;
|
|
18545
19541
|
this.workspaces = workspaces;
|
|
18546
19542
|
this.sessions = sessions;
|
|
@@ -18608,7 +19604,7 @@ const official$1 = ((require$1) => {
|
|
|
18608
19604
|
this.replaceMain(sessionId, navigation, "reveal", beforeOpen);
|
|
18609
19605
|
}
|
|
18610
19606
|
async forkSession(sessionId) {
|
|
18611
|
-
if (this.
|
|
19607
|
+
if (this.managedWorktreeGuard.blockSession(sessionId)) throw new Error("managed Session must be changed through its Worktree owner");
|
|
18612
19608
|
await this.sessions.fork({
|
|
18613
19609
|
sessionId,
|
|
18614
19610
|
increaseTitle: true
|
|
@@ -18621,7 +19617,7 @@ const official$1 = ((require$1) => {
|
|
|
18621
19617
|
const currentWorkspaceId = current === void 0 ? void 0 : workspace.items.find((item) => item.sessionIds.includes(current))?.workspaceId;
|
|
18622
19618
|
const recent = workspace.phase === "ready" && sessions.phase === "ready" ? recentWorkspace(workspace.items, sessions.byId) : void 0;
|
|
18623
19619
|
const target = workspaceId ?? currentWorkspaceId ?? recent;
|
|
18624
|
-
if (target !== void 0 && this.
|
|
19620
|
+
if (target !== void 0 && this.managedWorktreeGuard.blockWorkspace(target)) return;
|
|
18625
19621
|
if (target === void 0) {
|
|
18626
19622
|
this.clearMain();
|
|
18627
19623
|
return;
|
|
@@ -18631,7 +19627,6 @@ const official$1 = ((require$1) => {
|
|
|
18631
19627
|
});
|
|
18632
19628
|
}
|
|
18633
19629
|
async archiveSession(sessionId, options = {}) {
|
|
18634
|
-
if (this.ctx.get("__dshGitWorktreeManagedGuard").blockSession(sessionId)) throw new Error("managed Session must be changed through its Worktree owner");
|
|
18635
19630
|
await this.workspaces.archiveSession(sessionId, options);
|
|
18636
19631
|
if (this.mainReference?.sessionId === sessionId) this.clearMain();
|
|
18637
19632
|
}
|
|
@@ -19402,13 +20397,13 @@ const official$1 = ((require$1) => {
|
|
|
19402
20397
|
(0, react_jsx_runtime$1.jsx)("span", {
|
|
19403
20398
|
ref: titleRef,
|
|
19404
20399
|
className: Rows_module_css_default.title,
|
|
19405
|
-
onDoubleClick: row.blank
|
|
20400
|
+
onDoubleClick: row.blank ? void 0 : (e) => {
|
|
19406
20401
|
e.stopPropagation();
|
|
19407
20402
|
onRenameRequest(node.id, row.title);
|
|
19408
20403
|
},
|
|
19409
20404
|
children: title
|
|
19410
20405
|
}),
|
|
19411
|
-
protectedManagedSession && (0, react_jsx_runtime$1.jsx)("span", {
|
|
20406
|
+
protectedManagedSession && node.__dshGitWorktree.state !== "working" && (0, react_jsx_runtime$1.jsx)("span", {
|
|
19412
20407
|
className: "dsh-git-worktree-sidebar-badge",
|
|
19413
20408
|
"data-worktree-state": node.__dshGitWorktree.state,
|
|
19414
20409
|
children: node.__dshGitWorktree.label
|
|
@@ -21925,7 +22920,6 @@ const official$1 = ((require$1) => {
|
|
|
21925
22920
|
});
|
|
21926
22921
|
};
|
|
21927
22922
|
const renameSession = async (sessionId, title) => {
|
|
21928
|
-
if (ctx.get("__dshGitWorktreeManagedGuard").blockSession(sessionId)) throw new Error("managed Session must be changed through its Worktree owner");
|
|
21929
22923
|
const result = await sessions.using(sessionId, { source: "workspaceOperation" }, (reference) => reference.binding.session.rename(title));
|
|
21930
22924
|
if (!result.ok) throw new Error(result.error.message);
|
|
21931
22925
|
};
|
|
@@ -22218,6 +23212,7 @@ const official = ((require$1) => {
|
|
|
22218
23212
|
*/
|
|
22219
23213
|
constructor(ctx, directoryPicker, workspaces, sessions) {
|
|
22220
23214
|
super(ctx, "uiWorkspace");
|
|
23215
|
+
this.managedWorktreeGuard = ctx.get("__dshGitWorktreeManagedGuard");
|
|
22221
23216
|
this.directoryPicker = directoryPicker;
|
|
22222
23217
|
this.workspaces = workspaces;
|
|
22223
23218
|
this.sessions = sessions;
|
|
@@ -22259,7 +23254,7 @@ const official = ((require$1) => {
|
|
|
22259
23254
|
this.replaceMain(sessionId, navigation, beforeOpen);
|
|
22260
23255
|
}
|
|
22261
23256
|
async forkSession(sessionId) {
|
|
22262
|
-
if (this.
|
|
23257
|
+
if (this.managedWorktreeGuard.blockSession(sessionId)) throw new Error("managed Session must be changed through its Worktree owner");
|
|
22263
23258
|
const navigation = AbortSignal.any([this.ctx.layout.beginNavigation(), this.lifetime.signal]);
|
|
22264
23259
|
const childId = await this.sessions.fork({
|
|
22265
23260
|
sessionId,
|
|
@@ -22274,7 +23269,7 @@ const official = ((require$1) => {
|
|
|
22274
23269
|
const currentWorkspaceId = current === void 0 ? void 0 : workspace.items.find((item) => item.sessionIds.includes(current))?.workspaceId;
|
|
22275
23270
|
const recent = workspace.phase === "ready" && sessions.phase === "ready" ? recentWorkspace(workspace.items, sessions.byId) : void 0;
|
|
22276
23271
|
const target = workspaceId ?? currentWorkspaceId ?? recent;
|
|
22277
|
-
if (target !== void 0 && this.
|
|
23272
|
+
if (target !== void 0 && this.managedWorktreeGuard.blockWorkspace(target)) return;
|
|
22278
23273
|
if (target === void 0) {
|
|
22279
23274
|
this.clearMain();
|
|
22280
23275
|
return;
|
|
@@ -22284,7 +23279,6 @@ const official = ((require$1) => {
|
|
|
22284
23279
|
});
|
|
22285
23280
|
}
|
|
22286
23281
|
async archiveSession(sessionId) {
|
|
22287
|
-
if (this.ctx.get("__dshGitWorktreeManagedGuard").blockSession(sessionId)) throw new Error("managed Session must be changed through its Worktree owner");
|
|
22288
23282
|
await this.workspaces.archiveSession(sessionId);
|
|
22289
23283
|
if (this.mainReference?.sessionId === sessionId) this.clearMain();
|
|
22290
23284
|
}
|
|
@@ -23303,6 +24297,7 @@ const official = ((require$1) => {
|
|
|
23303
24297
|
icon: (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconArchiveOutline20, { size: 16 })
|
|
23304
24298
|
}
|
|
23305
24299
|
];
|
|
24300
|
+
const visibleSessionMenuItems = protectedManagedSession ? sessionMenuItems.filter((item) => item.id !== "fork") : sessionMenuItems;
|
|
23306
24301
|
return (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.HoverCard, {
|
|
23307
24302
|
anchor: (0, react_jsx_runtime$1.jsxs)("div", {
|
|
23308
24303
|
ref: rowRef,
|
|
@@ -23355,7 +24350,7 @@ const official = ((require$1) => {
|
|
|
23355
24350
|
className: Rows_module_css_default.title,
|
|
23356
24351
|
children: title
|
|
23357
24352
|
}),
|
|
23358
|
-
protectedManagedSession && (0, react_jsx_runtime$1.jsx)("span", {
|
|
24353
|
+
protectedManagedSession && node.__dshGitWorktree.state !== "working" && (0, react_jsx_runtime$1.jsx)("span", {
|
|
23359
24354
|
className: "dsh-git-worktree-sidebar-badge",
|
|
23360
24355
|
"data-worktree-state": node.__dshGitWorktree.state,
|
|
23361
24356
|
children: node.__dshGitWorktree.label
|
|
@@ -23365,14 +24360,14 @@ const official = ((require$1) => {
|
|
|
23365
24360
|
className: Rows_module_css_default.time,
|
|
23366
24361
|
children: timeLabel(row.updatedAt, now, t)
|
|
23367
24362
|
}),
|
|
23368
|
-
!row.blank &&
|
|
24363
|
+
!row.blank && (0, react_jsx_runtime$1.jsx)("span", {
|
|
23369
24364
|
className: Rows_module_css_default.rowActions,
|
|
23370
24365
|
children: (0, react_jsx_runtime$1.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
23371
24366
|
open: menuOpen,
|
|
23372
24367
|
onClose: () => {
|
|
23373
24368
|
setMenuOpen(false);
|
|
23374
24369
|
},
|
|
23375
|
-
items:
|
|
24370
|
+
items: visibleSessionMenuItems,
|
|
23376
24371
|
onSelect: (id) => {
|
|
23377
24372
|
setMenuOpen(false);
|
|
23378
24373
|
if (id === "rename") onRename(node.id, row.title);
|
|
@@ -25088,7 +26083,6 @@ const official = ((require$1) => {
|
|
|
25088
26083
|
searchSessions,
|
|
25089
26084
|
searchResultLimit: sessions.searchResultLimit,
|
|
25090
26085
|
renameSession: async (sessionId, title) => {
|
|
25091
|
-
if (ctx.get("__dshGitWorktreeManagedGuard").blockSession(sessionId)) throw new Error("managed Session must be changed through its Worktree owner");
|
|
25092
26086
|
const result = await sessions.using(sessionId, { source: "workspaceOperation" }, (reference) => reference.binding.session.rename(title));
|
|
25093
26087
|
if (!result.ok) throw new Error(result.error.message);
|
|
25094
26088
|
},
|