dsh-diff-approval 0.5.0 → 0.6.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/lib/client.js +370 -201
- package/lib/index.js +138 -1
- package/lib/types/client/PendingPanel.d.ts +1 -1
- package/lib/types/client/port.d.ts +7 -3
- package/lib/types/client/reference.d.ts +13 -11
- package/lib/types/client/slots.d.ts +7 -1
- package/lib/types/client/store.d.ts +5 -1
- package/lib/types/index.d.ts +1 -1
- package/lib/types/pending.d.ts +14 -0
- package/lib/types/types.d.ts +23 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -11582,30 +11582,21 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11582
11582
|
//#endregion
|
|
11583
11583
|
//#region lib/types/client/reference.js
|
|
11584
11584
|
/**
|
|
11585
|
-
*
|
|
11586
|
-
*
|
|
11587
|
-
*
|
|
11588
|
-
*
|
|
11589
|
-
*/
|
|
11590
|
-
/**
|
|
11591
|
-
* Last path segment of a file path, any separator style.
|
|
11592
|
-
* @param path - the path to shorten.
|
|
11593
|
-
* @returns the segment after the final separator.
|
|
11594
|
-
*/
|
|
11595
|
-
function basenameOf$1(path) {
|
|
11596
|
-
const normalized = path.replaceAll("\\", "/");
|
|
11597
|
-
return normalized.slice(normalized.lastIndexOf("/") + 1);
|
|
11598
|
-
}
|
|
11599
|
-
/**
|
|
11600
|
-
* The path shown in a copied reference: the short name when no other listed
|
|
11601
|
-
* file shares it, the full path otherwise.
|
|
11585
|
+
* The path embedded in a copied reference: workspace-relative (forward
|
|
11586
|
+
* slashes) when the file lives inside the current workspace, the absolute
|
|
11587
|
+
* path otherwise. A bare file name is never enough — a reference must resolve
|
|
11588
|
+
* to exactly one file.
|
|
11602
11589
|
* @param path - the selected file's path.
|
|
11603
|
-
* @param
|
|
11604
|
-
* @returns the
|
|
11590
|
+
* @param workspacePath - the current workspace root, or `undefined`.
|
|
11591
|
+
* @returns the reference path.
|
|
11605
11592
|
*/
|
|
11606
|
-
function
|
|
11607
|
-
|
|
11608
|
-
|
|
11593
|
+
function referencePathOf(path, workspacePath) {
|
|
11594
|
+
if (workspacePath === void 0 || workspacePath.length === 0) return path;
|
|
11595
|
+
const normalized = path.replaceAll("\\", "/");
|
|
11596
|
+
const root = workspacePath.replaceAll("\\", "/");
|
|
11597
|
+
const prefix = root.endsWith("/") ? root : `${root}/`;
|
|
11598
|
+
if (normalized.length > prefix.length && normalized.slice(0, prefix.length).toLowerCase() === prefix.toLowerCase()) return normalized.slice(prefix.length);
|
|
11599
|
+
return path;
|
|
11609
11600
|
}
|
|
11610
11601
|
/**
|
|
11611
11602
|
* Format one line range as a reference suffix: a single line number, or the
|
|
@@ -11620,17 +11611,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11620
11611
|
/**
|
|
11621
11612
|
* Build the clipboard text for a selected line range.
|
|
11622
11613
|
* @param path - the selected file's path.
|
|
11623
|
-
* @param
|
|
11614
|
+
* @param workspacePath - the current workspace root, or `undefined`.
|
|
11624
11615
|
* @param start - first selected line number.
|
|
11625
11616
|
* @param end - last selected line number.
|
|
11626
11617
|
* @returns the `path:range` reference text.
|
|
11627
11618
|
*/
|
|
11628
|
-
function referenceOf(path,
|
|
11629
|
-
return `${
|
|
11619
|
+
function referenceOf(path, workspacePath, start, end) {
|
|
11620
|
+
return `${referencePathOf(path, workspacePath)}:${lineRangeLabel(start, end)}`;
|
|
11630
11621
|
}
|
|
11631
11622
|
//#endregion
|
|
11632
11623
|
//#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
|
|
11633
|
-
const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 8px);height:42px;margin:4px -4px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_states{flex:1;min-height:0;padding:4px 12px 12px;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex:none;width:240px;min-height:0;padding:4px 8px 12px;overflow-y:auto}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_iconAction{justify-content:center;align-items:center;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);flex:1;padding:8px 10px;overflow:auto}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:8px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;user-select:none;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}";
|
|
11624
|
+
const css = ".F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 8px);height:42px;margin:4px -4px;display:flex;position:relative}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_states{flex:1;min-height:0;padding:4px 12px 12px;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex:none;width:240px;min-height:0;padding:4px 8px 12px;overflow-y:auto}.F1KBNa_resizeHandle{cursor:col-resize;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);flex:1;font-size:12px;line-height:18px;overflow:hidden}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);cursor:text;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;right:6px}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;display:table}.F1KBNa_line{height:22px;line-height:22px;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}";
|
|
11634
11625
|
const tagId = "dsh-diff-approval/PendingPanel.module.css";
|
|
11635
11626
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
11636
11627
|
const tag = document.createElement("style");
|
|
@@ -11640,67 +11631,69 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11640
11631
|
document.head.appendChild(tag);
|
|
11641
11632
|
}
|
|
11642
11633
|
var PendingPanel_module_css_default = {
|
|
11643
|
-
"
|
|
11644
|
-
"
|
|
11645
|
-
"
|
|
11646
|
-
"readError": "F1KBNa_readError",
|
|
11647
|
-
"diff": "F1KBNa_diff",
|
|
11648
|
-
"markerDel": "F1KBNa_markerDel",
|
|
11649
|
-
"group": "F1KBNa_group",
|
|
11650
|
-
"divergedHint": "F1KBNa_divergedHint",
|
|
11651
|
-
"detailEmpty": "F1KBNa_detailEmpty",
|
|
11652
|
-
"iconAction": "F1KBNa_iconAction",
|
|
11634
|
+
"diffHeader": "F1KBNa_diffHeader",
|
|
11635
|
+
"missing": "F1KBNa_missing",
|
|
11636
|
+
"resizeHandle": "F1KBNa_resizeHandle",
|
|
11653
11637
|
"diffBody": "F1KBNa_diffBody",
|
|
11654
11638
|
"rowPath": "F1KBNa_rowPath",
|
|
11655
|
-
"
|
|
11656
|
-
"
|
|
11657
|
-
"
|
|
11658
|
-
"
|
|
11659
|
-
"
|
|
11660
|
-
"
|
|
11661
|
-
"row": "F1KBNa_row",
|
|
11662
|
-
"kindHint": "F1KBNa_kindHint",
|
|
11663
|
-
"layer": "F1KBNa_layer",
|
|
11664
|
-
"rowMeta": "F1KBNa_rowMeta",
|
|
11665
|
-
"resizeHandle": "F1KBNa_resizeHandle",
|
|
11666
|
-
"footerButtons": "F1KBNa_footerButtons",
|
|
11667
|
-
"rowHead": "F1KBNa_rowHead",
|
|
11639
|
+
"expandExpanded": "F1KBNa_expandExpanded",
|
|
11640
|
+
"line": "F1KBNa_line",
|
|
11641
|
+
"headerActions": "F1KBNa_headerActions",
|
|
11642
|
+
"states": "F1KBNa_states",
|
|
11643
|
+
"detailEmpty": "F1KBNa_detailEmpty",
|
|
11644
|
+
"markerDel": "F1KBNa_markerDel",
|
|
11668
11645
|
"close": "F1KBNa_close",
|
|
11646
|
+
"markerAdd": "F1KBNa_markerAdd",
|
|
11647
|
+
"statusBar": "F1KBNa_statusBar",
|
|
11648
|
+
"diffStats": "F1KBNa_diffStats",
|
|
11649
|
+
"footerButtons": "F1KBNa_footerButtons",
|
|
11669
11650
|
"title": "F1KBNa_title",
|
|
11670
|
-
"
|
|
11671
|
-
"
|
|
11672
|
-
"missingHint": "F1KBNa_missingHint",
|
|
11673
|
-
"diffPath": "F1KBNa_diffPath",
|
|
11674
|
-
"detail": "F1KBNa_detail",
|
|
11675
|
-
"states": "F1KBNa_states",
|
|
11676
|
-
"headerActions": "F1KBNa_headerActions",
|
|
11677
|
-
"fileList": "F1KBNa_fileList",
|
|
11678
|
-
"langSelect": "F1KBNa_langSelect",
|
|
11651
|
+
"row": "F1KBNa_row",
|
|
11652
|
+
"delCount": "F1KBNa_delCount",
|
|
11679
11653
|
"expand": "F1KBNa_expand",
|
|
11680
|
-
"
|
|
11681
|
-
"statusAction": "F1KBNa_statusAction",
|
|
11682
|
-
"badgeLabel": "F1KBNa_badgeLabel",
|
|
11654
|
+
"layer": "F1KBNa_layer",
|
|
11683
11655
|
"diffActions": "F1KBNa_diffActions",
|
|
11684
|
-
"flexSpacer": "F1KBNa_flexSpacer",
|
|
11685
|
-
"kindTag": "F1KBNa_kindTag",
|
|
11686
|
-
"gutter": "F1KBNa_gutter",
|
|
11687
|
-
"markerAdd": "F1KBNa_markerAdd",
|
|
11688
|
-
"rows": "F1KBNa_rows",
|
|
11689
|
-
"delCount": "F1KBNa_delCount",
|
|
11690
11656
|
"context": "F1KBNa_context",
|
|
11691
|
-
"
|
|
11692
|
-
"
|
|
11657
|
+
"langSelect": "F1KBNa_langSelect",
|
|
11658
|
+
"kindTag": "F1KBNa_kindTag",
|
|
11659
|
+
"langLabel": "F1KBNa_langLabel",
|
|
11660
|
+
"flexSpacer": "F1KBNa_flexSpacer",
|
|
11661
|
+
"add": "F1KBNa_add",
|
|
11662
|
+
"badgeLabel": "F1KBNa_badgeLabel",
|
|
11663
|
+
"diffPath": "F1KBNa_diffPath",
|
|
11693
11664
|
"badgeCount": "F1KBNa_badgeCount",
|
|
11694
|
-
"
|
|
11695
|
-
"diffStats": "F1KBNa_diffStats",
|
|
11696
|
-
"split": "F1KBNa_split",
|
|
11697
|
-
"line": "F1KBNa_line",
|
|
11698
|
-
"expandExpanded": "F1KBNa_expandExpanded",
|
|
11665
|
+
"rows": "F1KBNa_rows",
|
|
11699
11666
|
"rail": "F1KBNa_rail",
|
|
11700
|
-
"
|
|
11701
|
-
"
|
|
11667
|
+
"lines": "F1KBNa_lines",
|
|
11668
|
+
"hint": "F1KBNa_hint",
|
|
11669
|
+
"code": "F1KBNa_code",
|
|
11670
|
+
"detail": "F1KBNa_detail",
|
|
11671
|
+
"readError": "F1KBNa_readError",
|
|
11672
|
+
"action": "F1KBNa_action",
|
|
11702
11673
|
"header": "F1KBNa_header",
|
|
11703
|
-
"
|
|
11674
|
+
"statusAction": "F1KBNa_statusAction",
|
|
11675
|
+
"panel": "F1KBNa_panel",
|
|
11676
|
+
"overviewMarker": "F1KBNa_overviewMarker",
|
|
11677
|
+
"blockActions": "F1KBNa_blockActions",
|
|
11678
|
+
"iconAction": "F1KBNa_iconAction",
|
|
11679
|
+
"rowHead": "F1KBNa_rowHead",
|
|
11680
|
+
"vSpacer": "F1KBNa_vSpacer",
|
|
11681
|
+
"missingHint": "F1KBNa_missingHint",
|
|
11682
|
+
"note": "F1KBNa_note",
|
|
11683
|
+
"gutter": "F1KBNa_gutter",
|
|
11684
|
+
"split": "F1KBNa_split",
|
|
11685
|
+
"divergedHint": "F1KBNa_divergedHint",
|
|
11686
|
+
"overviewRuler": "F1KBNa_overviewRuler",
|
|
11687
|
+
"rowMeta": "F1KBNa_rowMeta",
|
|
11688
|
+
"addCount": "F1KBNa_addCount",
|
|
11689
|
+
"diff": "F1KBNa_diff",
|
|
11690
|
+
"fileList": "F1KBNa_fileList",
|
|
11691
|
+
"actionPrimary": "F1KBNa_actionPrimary",
|
|
11692
|
+
"kindHint": "F1KBNa_kindHint",
|
|
11693
|
+
"diffBodyWrap": "F1KBNa_diffBodyWrap",
|
|
11694
|
+
"del": "F1KBNa_del",
|
|
11695
|
+
"badge": "F1KBNa_badge",
|
|
11696
|
+
"group": "F1KBNa_group"
|
|
11704
11697
|
};
|
|
11705
11698
|
//#endregion
|
|
11706
11699
|
//#region lib/types/client/PendingPanel.js
|
|
@@ -11752,7 +11745,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11752
11745
|
* does not re-render rows whose content, highlight, and focus are unchanged.
|
|
11753
11746
|
*/
|
|
11754
11747
|
const DiffRow = (0, react.memo)(function DiffRow(props) {
|
|
11755
|
-
const { index, row, runs, focused } = props;
|
|
11748
|
+
const { index, row, runs, focused, onRowHover } = props;
|
|
11756
11749
|
const lineNumber = row.kind === "del" ? row.oldLine : row.newLine;
|
|
11757
11750
|
const sideRuns = row.kind === "del" ? runs?.oldRuns : runs?.newRuns;
|
|
11758
11751
|
const lineRuns = lineNumber === void 0 ? void 0 : sideRuns?.[lineNumber - 1];
|
|
@@ -11765,6 +11758,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11765
11758
|
"data-diff-line": row.kind,
|
|
11766
11759
|
"data-diff-row": index,
|
|
11767
11760
|
"data-diff-focused": focused ? "" : void 0,
|
|
11761
|
+
onMouseEnter: () => {
|
|
11762
|
+
onRowHover(index);
|
|
11763
|
+
},
|
|
11768
11764
|
children: [
|
|
11769
11765
|
(0, react_jsx_runtime.jsx)("span", {
|
|
11770
11766
|
className: PendingPanel_module_css_default.gutter,
|
|
@@ -11782,6 +11778,48 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11782
11778
|
]
|
|
11783
11779
|
});
|
|
11784
11780
|
});
|
|
11781
|
+
/**
|
|
11782
|
+
* One diff block's old/new line ranges, 1-based inclusive, for block-level
|
|
11783
|
+
* keep/revert. A side with no lines (a pure addition or deletion) is empty;
|
|
11784
|
+
* its start is that side's insertion point — the line after the surrounding
|
|
11785
|
+
* context — so the host can insert there.
|
|
11786
|
+
* @param rows - the whole-file diff rows.
|
|
11787
|
+
* @param block - the block's row range.
|
|
11788
|
+
* @returns the old and new line ranges.
|
|
11789
|
+
*/
|
|
11790
|
+
function blockRangesOf(rows, block) {
|
|
11791
|
+
let oldStart = Infinity;
|
|
11792
|
+
let oldEnd = -Infinity;
|
|
11793
|
+
let newStart = Infinity;
|
|
11794
|
+
let newEnd = -Infinity;
|
|
11795
|
+
for (let index = block.start; index <= block.end; index++) {
|
|
11796
|
+
const row = rows[index];
|
|
11797
|
+
if (row === void 0) continue;
|
|
11798
|
+
if (row.oldLine !== void 0) {
|
|
11799
|
+
oldStart = Math.min(oldStart, row.oldLine);
|
|
11800
|
+
oldEnd = Math.max(oldEnd, row.oldLine);
|
|
11801
|
+
}
|
|
11802
|
+
if (row.newLine !== void 0) {
|
|
11803
|
+
newStart = Math.min(newStart, row.newLine);
|
|
11804
|
+
newEnd = Math.max(newEnd, row.newLine);
|
|
11805
|
+
}
|
|
11806
|
+
}
|
|
11807
|
+
const before = rows[block.start - 1];
|
|
11808
|
+
if (oldStart === Infinity) {
|
|
11809
|
+
oldStart = (before?.oldLine ?? 0) + 1;
|
|
11810
|
+
oldEnd = oldStart - 1;
|
|
11811
|
+
}
|
|
11812
|
+
if (newStart === Infinity) {
|
|
11813
|
+
newStart = (before?.newLine ?? 0) + 1;
|
|
11814
|
+
newEnd = newStart - 1;
|
|
11815
|
+
}
|
|
11816
|
+
return {
|
|
11817
|
+
oldStart,
|
|
11818
|
+
oldEnd,
|
|
11819
|
+
newStart,
|
|
11820
|
+
newEnd
|
|
11821
|
+
};
|
|
11822
|
+
}
|
|
11785
11823
|
/** Split a row list into maximal runs of non-context rows. */
|
|
11786
11824
|
function changeBlocksOf(diff) {
|
|
11787
11825
|
const blocks = [];
|
|
@@ -11866,48 +11904,48 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11866
11904
|
const stats = (0, react.useMemo)(() => computeWholeFileDiff(file.oldText, file.newText), [file.oldText, file.newText]);
|
|
11867
11905
|
return (0, react_jsx_runtime.jsx)("li", {
|
|
11868
11906
|
className: PendingPanel_module_css_default.row,
|
|
11869
|
-
children: (0, react_jsx_runtime.
|
|
11870
|
-
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
(
|
|
11878
|
-
|
|
11879
|
-
|
|
11880
|
-
|
|
11881
|
-
|
|
11907
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
11908
|
+
label: file.path,
|
|
11909
|
+
delayMs: 500,
|
|
11910
|
+
maxWidth: 560,
|
|
11911
|
+
children: (0, react_jsx_runtime.jsxs)("button", {
|
|
11912
|
+
type: "button",
|
|
11913
|
+
className: PendingPanel_module_css_default.rowHead,
|
|
11914
|
+
"data-selected": selected || void 0,
|
|
11915
|
+
onClick: () => {
|
|
11916
|
+
onSelect(file.id);
|
|
11917
|
+
},
|
|
11918
|
+
children: [
|
|
11919
|
+
(0, react_jsx_runtime.jsx)("span", {
|
|
11882
11920
|
className: PendingPanel_module_css_default.rowPath,
|
|
11883
11921
|
children: basenameOf(file.path)
|
|
11922
|
+
}),
|
|
11923
|
+
file.kind === "create" && (0, react_jsx_runtime.jsx)("span", {
|
|
11924
|
+
className: PendingPanel_module_css_default.kindTag,
|
|
11925
|
+
children: t("row.create")
|
|
11926
|
+
}),
|
|
11927
|
+
file.missing && (0, react_jsx_runtime.jsx)("span", {
|
|
11928
|
+
className: PendingPanel_module_css_default.missing,
|
|
11929
|
+
title: t("panel.missingHint"),
|
|
11930
|
+
children: t("panel.missing")
|
|
11931
|
+
}),
|
|
11932
|
+
(0, react_jsx_runtime.jsxs)("span", {
|
|
11933
|
+
className: PendingPanel_module_css_default.rowMeta,
|
|
11934
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
11935
|
+
className: PendingPanel_module_css_default.addCount,
|
|
11936
|
+
children: t("row.added", { added: stats.added })
|
|
11937
|
+
}), (0, react_jsx_runtime.jsx)("span", {
|
|
11938
|
+
className: PendingPanel_module_css_default.delCount,
|
|
11939
|
+
children: t("row.removed", { removed: stats.removed })
|
|
11940
|
+
})]
|
|
11884
11941
|
})
|
|
11885
|
-
|
|
11886
|
-
|
|
11887
|
-
className: PendingPanel_module_css_default.kindTag,
|
|
11888
|
-
children: t("row.create")
|
|
11889
|
-
}),
|
|
11890
|
-
file.missing && (0, react_jsx_runtime.jsx)("span", {
|
|
11891
|
-
className: PendingPanel_module_css_default.missing,
|
|
11892
|
-
title: t("panel.missingHint"),
|
|
11893
|
-
children: t("panel.missing")
|
|
11894
|
-
}),
|
|
11895
|
-
(0, react_jsx_runtime.jsxs)("span", {
|
|
11896
|
-
className: PendingPanel_module_css_default.rowMeta,
|
|
11897
|
-
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
11898
|
-
className: PendingPanel_module_css_default.addCount,
|
|
11899
|
-
children: t("row.added", { added: stats.added })
|
|
11900
|
-
}), (0, react_jsx_runtime.jsx)("span", {
|
|
11901
|
-
className: PendingPanel_module_css_default.delCount,
|
|
11902
|
-
children: t("row.removed", { removed: stats.removed })
|
|
11903
|
-
})]
|
|
11904
|
-
})
|
|
11905
|
-
]
|
|
11942
|
+
]
|
|
11943
|
+
})
|
|
11906
11944
|
})
|
|
11907
11945
|
});
|
|
11908
11946
|
}
|
|
11909
11947
|
/** The selected file's diff, actions, jump controls, and copy toolbar. */
|
|
11910
|
-
function PendingDiff({ file,
|
|
11948
|
+
function PendingDiff({ file, busy, workspacePath, t, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen }) {
|
|
11911
11949
|
const [langOverride, setLangOverride] = (0, react.useState)(void 0);
|
|
11912
11950
|
const [langMenuOpen, setLangMenuOpen] = (0, react.useState)(false);
|
|
11913
11951
|
const langMenuItems = (0, react.useMemo)(() => [{
|
|
@@ -11985,17 +12023,32 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
11985
12023
|
const [scrollTick, setScrollTick] = (0, react.useState)(0);
|
|
11986
12024
|
const [scrollTop, setScrollTop] = (0, react.useState)(0);
|
|
11987
12025
|
const [viewportHeight, setViewportHeight] = (0, react.useState)(0);
|
|
12026
|
+
const [hoveredBlock, setHoveredBlock] = (0, react.useState)(void 0);
|
|
11988
12027
|
const [selection, setSelection] = (0, react.useState)(void 0);
|
|
11989
12028
|
const [copied, setCopied] = (0, react.useState)(false);
|
|
11990
12029
|
(0, react.useEffect)(() => {
|
|
11991
12030
|
setFocus(0);
|
|
11992
12031
|
setScrollTop(0);
|
|
11993
12032
|
if (bodyRef.current !== null) bodyRef.current.scrollTop = 0;
|
|
12033
|
+
setHoveredBlock(void 0);
|
|
11994
12034
|
setSelection(void 0);
|
|
11995
12035
|
setLangOverride(void 0);
|
|
11996
12036
|
setLangMenuOpen(false);
|
|
11997
12037
|
setCopied(false);
|
|
11998
12038
|
}, [file.id]);
|
|
12039
|
+
const blockRanges = (0, react.useMemo)(() => {
|
|
12040
|
+
return model.blocks.map((block) => blockRangesOf(model.diff.rows, block));
|
|
12041
|
+
}, [model]);
|
|
12042
|
+
const blockIndexByRow = (0, react.useMemo)(() => {
|
|
12043
|
+
const map = /* @__PURE__ */ new Map();
|
|
12044
|
+
model.blocks.forEach((block, blockIndex) => {
|
|
12045
|
+
for (let index = block.start; index <= block.end; index++) map.set(index, blockIndex);
|
|
12046
|
+
});
|
|
12047
|
+
return map;
|
|
12048
|
+
}, [model]);
|
|
12049
|
+
const onRowHover = (0, react.useCallback)((index) => {
|
|
12050
|
+
setHoveredBlock(blockIndexByRow.get(index));
|
|
12051
|
+
}, [blockIndexByRow]);
|
|
11999
12052
|
const rows = model.diff.rows;
|
|
12000
12053
|
const rowCount = rows.length;
|
|
12001
12054
|
const viewport = viewportHeight > 0 ? viewportHeight : rowCount * ROW_HEIGHT_PX;
|
|
@@ -12066,9 +12119,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12066
12119
|
}, [file.id]);
|
|
12067
12120
|
const selectionReference = (() => {
|
|
12068
12121
|
if (selection === void 0) return void 0;
|
|
12069
|
-
const lineNumbers = model.diff.rows.slice(selection.start, selection.end + 1).map((row) => row.newLine
|
|
12122
|
+
const lineNumbers = model.diff.rows.slice(selection.start, selection.end + 1).map((row) => row.newLine).filter((number) => number !== void 0);
|
|
12070
12123
|
if (lineNumbers.length === 0) return void 0;
|
|
12071
|
-
return referenceOf(file.path,
|
|
12124
|
+
return referenceOf(file.path, workspacePath, Math.min(...lineNumbers), Math.max(...lineNumbers));
|
|
12072
12125
|
})();
|
|
12073
12126
|
const copySelection = (0, react.useCallback)(async () => {
|
|
12074
12127
|
if (selectionReference === void 0) return;
|
|
@@ -12104,27 +12157,35 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12104
12157
|
className: PendingPanel_module_css_default.diffPath,
|
|
12105
12158
|
children: file.path
|
|
12106
12159
|
}),
|
|
12107
|
-
(0, react_jsx_runtime.jsx)(
|
|
12108
|
-
|
|
12109
|
-
|
|
12110
|
-
|
|
12111
|
-
|
|
12112
|
-
|
|
12113
|
-
|
|
12114
|
-
|
|
12115
|
-
|
|
12116
|
-
|
|
12160
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12161
|
+
label: t("action.openFile"),
|
|
12162
|
+
side: "bottom",
|
|
12163
|
+
delayMs: 500,
|
|
12164
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
12165
|
+
type: "button",
|
|
12166
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12167
|
+
"data-diff-open": true,
|
|
12168
|
+
"aria-label": t("action.openFile"),
|
|
12169
|
+
onClick: () => {
|
|
12170
|
+
onOpen(file.sessionId, file.id, "open");
|
|
12171
|
+
},
|
|
12172
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBrowseOutline16, { size: 14 })
|
|
12173
|
+
})
|
|
12117
12174
|
}),
|
|
12118
|
-
(0, react_jsx_runtime.jsx)(
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12175
|
+
(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12176
|
+
label: t("action.revealFile"),
|
|
12177
|
+
side: "bottom",
|
|
12178
|
+
delayMs: 500,
|
|
12179
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
12180
|
+
type: "button",
|
|
12181
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12182
|
+
"data-diff-reveal": true,
|
|
12183
|
+
"aria-label": t("action.revealFile"),
|
|
12184
|
+
onClick: () => {
|
|
12185
|
+
onOpen(file.sessionId, file.id, "reveal");
|
|
12186
|
+
},
|
|
12187
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, { size: 14 })
|
|
12188
|
+
})
|
|
12128
12189
|
})
|
|
12129
12190
|
]
|
|
12130
12191
|
}),
|
|
@@ -12142,33 +12203,41 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12142
12203
|
className: PendingPanel_module_css_default.kindHint,
|
|
12143
12204
|
children: t("panel.createHint")
|
|
12144
12205
|
}),
|
|
12145
|
-
model.blocks.length > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(
|
|
12146
|
-
|
|
12147
|
-
|
|
12148
|
-
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
|
|
12162
|
-
|
|
12163
|
-
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12206
|
+
model.blocks.length > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12207
|
+
label: t("action.prevDiff"),
|
|
12208
|
+
side: "bottom",
|
|
12209
|
+
delayMs: 500,
|
|
12210
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
12211
|
+
type: "button",
|
|
12212
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12213
|
+
"data-diff-prev": true,
|
|
12214
|
+
"aria-label": t("action.prevDiff"),
|
|
12215
|
+
disabled: busy,
|
|
12216
|
+
onClick: () => {
|
|
12217
|
+
jump(-1);
|
|
12218
|
+
},
|
|
12219
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 14 })
|
|
12220
|
+
})
|
|
12221
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12222
|
+
label: t("action.nextDiff"),
|
|
12223
|
+
side: "bottom",
|
|
12224
|
+
delayMs: 500,
|
|
12225
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
12226
|
+
type: "button",
|
|
12227
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.iconAction}`,
|
|
12228
|
+
"data-diff-next": true,
|
|
12229
|
+
"aria-label": t("action.nextDiff"),
|
|
12230
|
+
disabled: busy,
|
|
12231
|
+
onClick: () => {
|
|
12232
|
+
jump(1);
|
|
12233
|
+
},
|
|
12234
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
12235
|
+
})
|
|
12167
12236
|
})] }),
|
|
12168
12237
|
(0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
|
|
12169
12238
|
(0, react_jsx_runtime.jsx)("button", {
|
|
12170
12239
|
type: "button",
|
|
12171
|
-
className: PendingPanel_module_css_default.action
|
|
12240
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
12172
12241
|
"data-diff-keep": true,
|
|
12173
12242
|
disabled: busy,
|
|
12174
12243
|
onClick: () => {
|
|
@@ -12194,12 +12263,15 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12194
12263
|
}),
|
|
12195
12264
|
(0, react_jsx_runtime.jsxs)("div", {
|
|
12196
12265
|
className: PendingPanel_module_css_default.diffBodyWrap,
|
|
12197
|
-
children: [(0, react_jsx_runtime.
|
|
12266
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
12198
12267
|
className: PendingPanel_module_css_default.diffBody,
|
|
12199
12268
|
ref: bodyRef,
|
|
12200
12269
|
onScroll,
|
|
12270
|
+
onMouseLeave: () => {
|
|
12271
|
+
setHoveredBlock(void 0);
|
|
12272
|
+
},
|
|
12201
12273
|
"data-diff-body": true,
|
|
12202
|
-
children: (0, react_jsx_runtime.jsxs)("div", {
|
|
12274
|
+
children: [(0, react_jsx_runtime.jsxs)("div", {
|
|
12203
12275
|
className: PendingPanel_module_css_default.lines,
|
|
12204
12276
|
style: { minWidth: `max(100%, ${widestLine}ch)` },
|
|
12205
12277
|
children: [
|
|
@@ -12214,7 +12286,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12214
12286
|
index,
|
|
12215
12287
|
row,
|
|
12216
12288
|
runs,
|
|
12217
|
-
focused: inFocusedBlock(index)
|
|
12289
|
+
focused: inFocusedBlock(index),
|
|
12290
|
+
onRowHover
|
|
12218
12291
|
}, index);
|
|
12219
12292
|
}),
|
|
12220
12293
|
end < rowCount && (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -12223,7 +12296,30 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12223
12296
|
"aria-hidden": "true"
|
|
12224
12297
|
})
|
|
12225
12298
|
]
|
|
12226
|
-
})
|
|
12299
|
+
}), hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
|
|
12300
|
+
className: PendingPanel_module_css_default.blockActions,
|
|
12301
|
+
"data-diff-block-actions": true,
|
|
12302
|
+
style: { top: model.blocks[hoveredBlock].start * ROW_HEIGHT_PX },
|
|
12303
|
+
children: [(0, react_jsx_runtime.jsx)("button", {
|
|
12304
|
+
type: "button",
|
|
12305
|
+
className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
|
|
12306
|
+
"data-diff-block-keep": true,
|
|
12307
|
+
disabled: busy,
|
|
12308
|
+
onClick: () => {
|
|
12309
|
+
onBlockKeep(file.sessionId, file.id, blockRanges[hoveredBlock]);
|
|
12310
|
+
},
|
|
12311
|
+
children: t("action.keep")
|
|
12312
|
+
}), (0, react_jsx_runtime.jsx)("button", {
|
|
12313
|
+
type: "button",
|
|
12314
|
+
className: PendingPanel_module_css_default.action,
|
|
12315
|
+
"data-diff-block-revert": true,
|
|
12316
|
+
disabled: busy,
|
|
12317
|
+
onClick: () => {
|
|
12318
|
+
onBlockRevert(file.sessionId, file.id, blockRanges[hoveredBlock]);
|
|
12319
|
+
},
|
|
12320
|
+
children: t("action.revert")
|
|
12321
|
+
})]
|
|
12322
|
+
})]
|
|
12227
12323
|
}), rulerMarkers.length > 0 && (0, react_jsx_runtime.jsx)("div", {
|
|
12228
12324
|
className: PendingPanel_module_css_default.overviewRuler,
|
|
12229
12325
|
"data-diff-approval-ruler": true,
|
|
@@ -12274,19 +12370,23 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12274
12370
|
onClose: () => {
|
|
12275
12371
|
setLangMenuOpen(false);
|
|
12276
12372
|
},
|
|
12277
|
-
anchor: (0, react_jsx_runtime.
|
|
12278
|
-
|
|
12279
|
-
|
|
12280
|
-
|
|
12281
|
-
|
|
12282
|
-
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12289
|
-
|
|
12373
|
+
anchor: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12374
|
+
label: t("action.langSelect"),
|
|
12375
|
+
side: "top",
|
|
12376
|
+
delayMs: 500,
|
|
12377
|
+
children: (0, react_jsx_runtime.jsxs)("button", {
|
|
12378
|
+
type: "button",
|
|
12379
|
+
className: PendingPanel_module_css_default.langSelect,
|
|
12380
|
+
"data-diff-lang": true,
|
|
12381
|
+
"aria-label": t("action.langSelect"),
|
|
12382
|
+
onClick: () => {
|
|
12383
|
+
setLangMenuOpen((value) => !value);
|
|
12384
|
+
},
|
|
12385
|
+
children: [(0, react_jsx_runtime.jsx)("span", {
|
|
12386
|
+
className: PendingPanel_module_css_default.langLabel,
|
|
12387
|
+
children: langLabel
|
|
12388
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 12 })]
|
|
12389
|
+
})
|
|
12290
12390
|
})
|
|
12291
12391
|
})
|
|
12292
12392
|
]
|
|
@@ -12295,7 +12395,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12295
12395
|
});
|
|
12296
12396
|
}
|
|
12297
12397
|
/** Render the pending-edit review panel and its unified footer action. */
|
|
12298
|
-
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onOpen, t }) {
|
|
12398
|
+
function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, t }) {
|
|
12299
12399
|
const current = useSessions((state) => state.current);
|
|
12300
12400
|
const snapshot = usePending((snapshot) => snapshot);
|
|
12301
12401
|
const [open, setOpen] = (0, react.useState)(false);
|
|
@@ -12438,26 +12538,34 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12438
12538
|
children: t("panel.title")
|
|
12439
12539
|
}), (0, react_jsx_runtime.jsxs)("div", {
|
|
12440
12540
|
className: PendingPanel_module_css_default.headerActions,
|
|
12441
|
-
children: [(0, react_jsx_runtime.jsx)(
|
|
12442
|
-
|
|
12443
|
-
|
|
12444
|
-
|
|
12445
|
-
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
|
|
12449
|
-
|
|
12450
|
-
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
|
|
12460
|
-
|
|
12541
|
+
children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12542
|
+
label: t(expanded ? "action.exitFullscreen" : "action.expand"),
|
|
12543
|
+
side: "bottom",
|
|
12544
|
+
delayMs: 500,
|
|
12545
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
12546
|
+
type: "button",
|
|
12547
|
+
className: expanded ? `${PendingPanel_module_css_default.expand} ${PendingPanel_module_css_default.expandExpanded}` : PendingPanel_module_css_default.expand,
|
|
12548
|
+
"data-diff-approval-expand": true,
|
|
12549
|
+
"aria-label": t(expanded ? "action.exitFullscreen" : "action.expand"),
|
|
12550
|
+
onClick: () => {
|
|
12551
|
+
setExpanded((value) => !value);
|
|
12552
|
+
},
|
|
12553
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFullscreenOutline16, { size: 14 })
|
|
12554
|
+
})
|
|
12555
|
+
}), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
12556
|
+
label: t("action.close"),
|
|
12557
|
+
side: "bottom",
|
|
12558
|
+
delayMs: 500,
|
|
12559
|
+
children: (0, react_jsx_runtime.jsx)("button", {
|
|
12560
|
+
type: "button",
|
|
12561
|
+
className: PendingPanel_module_css_default.close,
|
|
12562
|
+
"data-diff-approval-close": true,
|
|
12563
|
+
"aria-label": t("action.close"),
|
|
12564
|
+
onClick: () => {
|
|
12565
|
+
setOpen(false);
|
|
12566
|
+
},
|
|
12567
|
+
children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseOutline16, { size: 14 })
|
|
12568
|
+
})
|
|
12461
12569
|
})]
|
|
12462
12570
|
})]
|
|
12463
12571
|
}), snapshot.error !== void 0 || !snapshot.read || files.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -12510,11 +12618,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12510
12618
|
children: t("panel.selectHint")
|
|
12511
12619
|
}) : (0, react_jsx_runtime.jsx)(PendingDiff, {
|
|
12512
12620
|
file: selectedFile,
|
|
12513
|
-
files,
|
|
12514
12621
|
busy: snapshot.busy.has(selectedFile.id),
|
|
12622
|
+
workspacePath: snapshot.workspacePath,
|
|
12515
12623
|
t,
|
|
12516
12624
|
onKeep,
|
|
12517
12625
|
onRevert,
|
|
12626
|
+
onBlockKeep,
|
|
12627
|
+
onBlockRevert,
|
|
12518
12628
|
onOpen
|
|
12519
12629
|
})
|
|
12520
12630
|
})
|
|
@@ -12562,7 +12672,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12562
12672
|
function createDiffApprovalPort(rpc) {
|
|
12563
12673
|
return {
|
|
12564
12674
|
async list(sessionId) {
|
|
12565
|
-
return
|
|
12675
|
+
return listValueOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "list", { sessionId }));
|
|
12566
12676
|
},
|
|
12567
12677
|
async keep(sessionId, id) {
|
|
12568
12678
|
return actionOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "keep", {
|
|
@@ -12576,6 +12686,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12576
12686
|
id
|
|
12577
12687
|
}));
|
|
12578
12688
|
},
|
|
12689
|
+
async blockKeep(sessionId, id, block) {
|
|
12690
|
+
return actionOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "block-keep", {
|
|
12691
|
+
sessionId,
|
|
12692
|
+
id,
|
|
12693
|
+
block
|
|
12694
|
+
}));
|
|
12695
|
+
},
|
|
12696
|
+
async blockRevert(sessionId, id, block) {
|
|
12697
|
+
return actionOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "block-revert", {
|
|
12698
|
+
sessionId,
|
|
12699
|
+
id,
|
|
12700
|
+
block
|
|
12701
|
+
}));
|
|
12702
|
+
},
|
|
12579
12703
|
async open(sessionId, id, action) {
|
|
12580
12704
|
return openOf(await rpc.call(DIFF_APPROVAL_CHANNEL, "open", {
|
|
12581
12705
|
sessionId,
|
|
@@ -12608,18 +12732,23 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12608
12732
|
};
|
|
12609
12733
|
}
|
|
12610
12734
|
/** Narrow the list endpoint's value; a malformed wire value is a read failure. */
|
|
12611
|
-
function
|
|
12735
|
+
function listValueOf(result) {
|
|
12612
12736
|
if (!result.ok) throw new Error(`${result.error.code}: ${result.error.message}`);
|
|
12613
12737
|
const value = result.value;
|
|
12614
12738
|
if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("list returned a malformed value");
|
|
12615
12739
|
const rows = value.files;
|
|
12616
12740
|
if (!Array.isArray(rows)) throw new Error("list returned a malformed value");
|
|
12741
|
+
const workspace = value.workspacePath;
|
|
12742
|
+
const workspacePath = typeof workspace === "string" && workspace.length > 0 ? workspace : void 0;
|
|
12617
12743
|
const files = [];
|
|
12618
12744
|
for (const row of rows) {
|
|
12619
12745
|
const file = pendingFileOf(row);
|
|
12620
12746
|
if (file !== void 0) files.push(file);
|
|
12621
12747
|
}
|
|
12622
|
-
return
|
|
12748
|
+
return {
|
|
12749
|
+
files,
|
|
12750
|
+
workspacePath
|
|
12751
|
+
};
|
|
12623
12752
|
}
|
|
12624
12753
|
/** Narrow one action endpoint's value; a malformed wire value is an action failure. */
|
|
12625
12754
|
function actionOf(result) {
|
|
@@ -12706,16 +12835,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12706
12835
|
return;
|
|
12707
12836
|
}
|
|
12708
12837
|
try {
|
|
12709
|
-
const files = await port.list(sessionId);
|
|
12838
|
+
const { files, workspacePath } = await port.list(sessionId);
|
|
12710
12839
|
publish({
|
|
12711
12840
|
read: true,
|
|
12712
12841
|
files,
|
|
12842
|
+
workspacePath,
|
|
12713
12843
|
busy: EMPTY_BUSY
|
|
12714
12844
|
});
|
|
12715
12845
|
} catch (error) {
|
|
12716
12846
|
publish({
|
|
12717
12847
|
read: true,
|
|
12718
12848
|
files: snapshot.files,
|
|
12849
|
+
workspacePath: snapshot.workspacePath,
|
|
12719
12850
|
error: error instanceof Error ? error.message : String(error),
|
|
12720
12851
|
busy: snapshot.busy
|
|
12721
12852
|
});
|
|
@@ -12731,6 +12862,42 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12731
12862
|
await port.revert(sessionId, id);
|
|
12732
12863
|
});
|
|
12733
12864
|
},
|
|
12865
|
+
async blockKeep(sessionId, id, block) {
|
|
12866
|
+
const { error: _cleared, ...base } = snapshot;
|
|
12867
|
+
publish({
|
|
12868
|
+
...base,
|
|
12869
|
+
busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
|
|
12870
|
+
});
|
|
12871
|
+
try {
|
|
12872
|
+
await port.blockKeep(sessionId, id, block);
|
|
12873
|
+
} catch (error) {
|
|
12874
|
+
publish({
|
|
12875
|
+
...snapshot,
|
|
12876
|
+
error: error instanceof Error ? error.message : String(error),
|
|
12877
|
+
busy: new Set([...snapshot.busy].filter((busy) => busy !== id))
|
|
12878
|
+
});
|
|
12879
|
+
return;
|
|
12880
|
+
}
|
|
12881
|
+
await this.refresh(sessionId);
|
|
12882
|
+
},
|
|
12883
|
+
async blockRevert(sessionId, id, block) {
|
|
12884
|
+
const { error: _cleared, ...base } = snapshot;
|
|
12885
|
+
publish({
|
|
12886
|
+
...base,
|
|
12887
|
+
busy: /* @__PURE__ */ new Set([...snapshot.busy, id])
|
|
12888
|
+
});
|
|
12889
|
+
try {
|
|
12890
|
+
await port.blockRevert(sessionId, id, block);
|
|
12891
|
+
} catch (error) {
|
|
12892
|
+
publish({
|
|
12893
|
+
...snapshot,
|
|
12894
|
+
error: error instanceof Error ? error.message : String(error),
|
|
12895
|
+
busy: new Set([...snapshot.busy].filter((busy) => busy !== id))
|
|
12896
|
+
});
|
|
12897
|
+
return;
|
|
12898
|
+
}
|
|
12899
|
+
await this.refresh(sessionId);
|
|
12900
|
+
},
|
|
12734
12901
|
async open(sessionId, id, action) {
|
|
12735
12902
|
try {
|
|
12736
12903
|
await port.open(sessionId, id, action);
|
|
@@ -12860,6 +13027,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
|
|
|
12860
13027
|
},
|
|
12861
13028
|
onKeep: (sessionId, path) => store.keep(sessionId, path),
|
|
12862
13029
|
onRevert: (sessionId, path) => store.revert(sessionId, path),
|
|
13030
|
+
onBlockKeep: (sessionId, id, block) => store.blockKeep(sessionId, id, block),
|
|
13031
|
+
onBlockRevert: (sessionId, id, block) => store.blockRevert(sessionId, id, block),
|
|
12863
13032
|
onOpen: (sessionId, id, action) => store.open(sessionId, id, action)
|
|
12864
13033
|
})
|
|
12865
13034
|
}, PendingPanel));
|
package/lib/index.js
CHANGED
|
@@ -108,6 +108,28 @@ var PendingDiffStore = class {
|
|
|
108
108
|
for (const [key, indexedId] of this.pathIndex) if (indexedId === id) this.pathIndex.delete(key);
|
|
109
109
|
return true;
|
|
110
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Advance one entry's tracked content after a block-level keep/revert. The
|
|
113
|
+
* entry keeps its id and path; only the given side's text and capture time
|
|
114
|
+
* move. When the caller decides the sides now match, it removes the entry
|
|
115
|
+
* instead of updating it.
|
|
116
|
+
* @param sessionId - the owning session.
|
|
117
|
+
* @param id - the entry id.
|
|
118
|
+
* @param patch - the side to advance (`oldText` for keep, `newText` for revert).
|
|
119
|
+
* @returns whether the entry changed.
|
|
120
|
+
*/
|
|
121
|
+
update(sessionId, id, patch) {
|
|
122
|
+
const key = entryKey(sessionId, id);
|
|
123
|
+
const entry = this.entries.get(key);
|
|
124
|
+
if (entry === void 0) return false;
|
|
125
|
+
const next = {
|
|
126
|
+
...entry,
|
|
127
|
+
...patch,
|
|
128
|
+
updatedAt: Date.now()
|
|
129
|
+
};
|
|
130
|
+
this.entries.set(key, next);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
111
133
|
/** Total entry count across all sessions. */
|
|
112
134
|
get size() {
|
|
113
135
|
return this.entries.size;
|
|
@@ -760,7 +782,10 @@ function apply(ctx, config) {
|
|
|
760
782
|
if (sessionId === void 0) return rpcError("sessionId must be a non-empty string");
|
|
761
783
|
return {
|
|
762
784
|
ok: true,
|
|
763
|
-
value: {
|
|
785
|
+
value: {
|
|
786
|
+
files: await listWithState(await workspaceEntries(sessionId)),
|
|
787
|
+
workspacePath: workspaceOf(sessionId)?.path
|
|
788
|
+
}
|
|
764
789
|
};
|
|
765
790
|
}
|
|
766
791
|
case "keep": {
|
|
@@ -797,6 +822,51 @@ function apply(ctx, config) {
|
|
|
797
822
|
value: { outcome: "reverted" }
|
|
798
823
|
};
|
|
799
824
|
}
|
|
825
|
+
case "block-keep": {
|
|
826
|
+
const blockTarget = blockTargetOf(payload);
|
|
827
|
+
if (blockTarget === void 0) return rpcError("sessionId, id, and block must be valid");
|
|
828
|
+
await ensureLoaded(blockTarget.sessionId);
|
|
829
|
+
const entry = store.get(blockTarget.sessionId, blockTarget.id);
|
|
830
|
+
if (entry === void 0) return {
|
|
831
|
+
ok: true,
|
|
832
|
+
value: { outcome: "missing" }
|
|
833
|
+
};
|
|
834
|
+
const accepted = contentRangeOf(entry.newText, blockTarget.block.newStart, blockTarget.block.newEnd);
|
|
835
|
+
const updatedOld = replaceContentLines(entry.oldText, blockTarget.block.oldStart, blockTarget.block.oldEnd, accepted);
|
|
836
|
+
if (updatedOld === entry.newText) store.remove(blockTarget.sessionId, blockTarget.id);
|
|
837
|
+
else store.update(blockTarget.sessionId, blockTarget.id, { oldText: updatedOld });
|
|
838
|
+
await persistSession(blockTarget.sessionId);
|
|
839
|
+
return {
|
|
840
|
+
ok: true,
|
|
841
|
+
value: { outcome: "kept" }
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
case "block-revert": {
|
|
845
|
+
const blockTarget = blockTargetOf(payload);
|
|
846
|
+
if (blockTarget === void 0) return rpcError("sessionId, id, and block must be valid");
|
|
847
|
+
await ensureLoaded(blockTarget.sessionId);
|
|
848
|
+
const entry = store.get(blockTarget.sessionId, blockTarget.id);
|
|
849
|
+
if (entry === void 0) return {
|
|
850
|
+
ok: true,
|
|
851
|
+
value: { outcome: "missing" }
|
|
852
|
+
};
|
|
853
|
+
const restored = contentRangeOf(entry.oldText, blockTarget.block.oldStart, blockTarget.block.oldEnd);
|
|
854
|
+
const updatedNew = replaceContentLines(entry.newText, blockTarget.block.newStart, blockTarget.block.newEnd, restored);
|
|
855
|
+
try {
|
|
856
|
+
const resolved = await ctx.fs.resolve(entry.path, { signal });
|
|
857
|
+
if (entry.kind === "create" && updatedNew === "") await rm(ctx.fs.processPath(resolved), { force: true });
|
|
858
|
+
else await ctx.fs.writeText(resolved, updatedNew, void 0, signal);
|
|
859
|
+
} catch (error) {
|
|
860
|
+
return rpcError(`block revert failed: ${errorMessage(error)}`);
|
|
861
|
+
}
|
|
862
|
+
if (updatedNew === entry.oldText) store.remove(blockTarget.sessionId, blockTarget.id);
|
|
863
|
+
else store.update(blockTarget.sessionId, blockTarget.id, { newText: updatedNew });
|
|
864
|
+
await persistSession(blockTarget.sessionId);
|
|
865
|
+
return {
|
|
866
|
+
ok: true,
|
|
867
|
+
value: { outcome: "reverted" }
|
|
868
|
+
};
|
|
869
|
+
}
|
|
800
870
|
case "open": {
|
|
801
871
|
const target = openTargetOf(payload);
|
|
802
872
|
if (target === void 0) return rpcError("sessionId, id, and action must be valid");
|
|
@@ -836,6 +906,73 @@ function sessionOf(payload) {
|
|
|
836
906
|
const value = payload.sessionId;
|
|
837
907
|
return typeof value === "string" && value.length > 0 ? SessionId(value) : void 0;
|
|
838
908
|
}
|
|
909
|
+
/** The content lines of `text`, matching the diff's line numbering (a single
|
|
910
|
+
trailing newline is a terminator, not an extra empty line). */
|
|
911
|
+
function contentLinesOf(text) {
|
|
912
|
+
if (text === "") return [];
|
|
913
|
+
const lines = text.split("\n");
|
|
914
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
915
|
+
return lines;
|
|
916
|
+
}
|
|
917
|
+
/** Rebuild text from content lines, keeping `original`'s trailing-newline convention. */
|
|
918
|
+
function fromContentLines(original, lines) {
|
|
919
|
+
if (lines.length === 0) return "";
|
|
920
|
+
return lines.join("\n") + (original.endsWith("\n") ? "\n" : "");
|
|
921
|
+
}
|
|
922
|
+
/** The content lines [start..end] (1-based inclusive) of `text`; empty when start > end. */
|
|
923
|
+
function contentRangeOf(text, start, end) {
|
|
924
|
+
if (start > end) return [];
|
|
925
|
+
return contentLinesOf(text).slice(start - 1, end);
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Replace the content lines [start..end] (1-based) of `text` with `replacement`
|
|
929
|
+
* lines. An empty range (`start > end`) inserts before line `start`. Out-of-range
|
|
930
|
+
* bounds clamp; the trailing-newline convention of `text` is preserved.
|
|
931
|
+
*/
|
|
932
|
+
function replaceContentLines(text, start, end, replacement) {
|
|
933
|
+
const lines = contentLinesOf(text);
|
|
934
|
+
const count = lines.length;
|
|
935
|
+
if (start > end) {
|
|
936
|
+
const at = Math.min(Math.max(start, 1), count + 1);
|
|
937
|
+
return fromContentLines(text, [
|
|
938
|
+
...lines.slice(0, at - 1),
|
|
939
|
+
...replacement,
|
|
940
|
+
...lines.slice(at - 1)
|
|
941
|
+
]);
|
|
942
|
+
}
|
|
943
|
+
const s = Math.min(Math.max(start, 1), count + 1);
|
|
944
|
+
const e = Math.min(Math.max(end, 1), count);
|
|
945
|
+
if (s > e) return text;
|
|
946
|
+
return fromContentLines(text, [
|
|
947
|
+
...lines.slice(0, s - 1),
|
|
948
|
+
...replacement,
|
|
949
|
+
...lines.slice(e)
|
|
950
|
+
]);
|
|
951
|
+
}
|
|
952
|
+
/** Narrow a wire payload to one block keep/revert target. */
|
|
953
|
+
function blockTargetOf(payload) {
|
|
954
|
+
const target = targetOf(payload);
|
|
955
|
+
if (target === void 0) return void 0;
|
|
956
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) return void 0;
|
|
957
|
+
const block = payload.block;
|
|
958
|
+
if (typeof block !== "object" || block === null || Array.isArray(block)) return void 0;
|
|
959
|
+
const { oldStart, oldEnd, newStart, newEnd } = block;
|
|
960
|
+
if (![
|
|
961
|
+
oldStart,
|
|
962
|
+
oldEnd,
|
|
963
|
+
newStart,
|
|
964
|
+
newEnd
|
|
965
|
+
].every((value) => typeof value === "number" && Number.isFinite(value))) return void 0;
|
|
966
|
+
return {
|
|
967
|
+
...target,
|
|
968
|
+
block: {
|
|
969
|
+
oldStart,
|
|
970
|
+
oldEnd,
|
|
971
|
+
newStart,
|
|
972
|
+
newEnd
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
}
|
|
839
976
|
/** Narrow a wire payload to one keep/revert target. */
|
|
840
977
|
function targetOf(payload) {
|
|
841
978
|
const sessionId = sessionOf(payload);
|
|
@@ -4,4 +4,4 @@ import type { PendingPanelFace } from './slots.ts';
|
|
|
4
4
|
/** Full panel props composed by the sidebar footer-action slot. */
|
|
5
5
|
export type PendingPanelProps = PropsRuntime<'sidebar.footer.action'> & InjectFace<PendingPanelFace> & PropsLocale<'diff-approval'>;
|
|
6
6
|
/** Render the pending-edit review panel and its unified footer action. */
|
|
7
|
-
export declare function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onOpen, t, }: PendingPanelProps): import("react").JSX.Element;
|
|
7
|
+
export declare function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, t, }: PendingPanelProps): import("react").JSX.Element;
|
|
@@ -5,17 +5,21 @@
|
|
|
5
5
|
* @module dsh-diff-approval/client/port
|
|
6
6
|
*/
|
|
7
7
|
import type { ClientConnectionRpc, SessionId } from '@deepseek-ai/dsh-client-connection/client';
|
|
8
|
-
import type { DiffApprovalActionValue, DiffApprovalOpenAction, DiffApprovalOpenValue
|
|
8
|
+
import type { DiffApprovalActionValue, DiffApprovalBlockRange, DiffApprovalListValue, DiffApprovalOpenAction, DiffApprovalOpenValue } from '../types.ts';
|
|
9
9
|
/** The channel the host half registers and this port calls. */
|
|
10
10
|
export declare const DIFF_APPROVAL_CHANNEL = "/diff-approval";
|
|
11
11
|
/** This package's business verbs over the review channel. */
|
|
12
12
|
export interface DiffApprovalPort {
|
|
13
|
-
/** Read one session's pending entries, oldest capture first. */
|
|
14
|
-
list(sessionId: SessionId): Promise<
|
|
13
|
+
/** Read one session's pending entries (plus its workspace root), oldest capture first. */
|
|
14
|
+
list(sessionId: SessionId): Promise<DiffApprovalListValue>;
|
|
15
15
|
/** Keep one operation. */
|
|
16
16
|
keep(sessionId: SessionId, id: string): Promise<DiffApprovalActionValue>;
|
|
17
17
|
/** Revert one operation. */
|
|
18
18
|
revert(sessionId: SessionId, id: string): Promise<DiffApprovalActionValue>;
|
|
19
|
+
/** Keep one diff block (accept its change into the tracked baseline). */
|
|
20
|
+
blockKeep(sessionId: SessionId, id: string, block: DiffApprovalBlockRange): Promise<DiffApprovalActionValue>;
|
|
21
|
+
/** Revert one diff block (restore its old lines in the file). */
|
|
22
|
+
blockRevert(sessionId: SessionId, id: string, block: DiffApprovalBlockRange): Promise<DiffApprovalActionValue>;
|
|
19
23
|
/** Open one file with its default application or reveal it in the folder. */
|
|
20
24
|
open(sessionId: SessionId, id: string, action: DiffApprovalOpenAction): Promise<DiffApprovalOpenValue>;
|
|
21
25
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Reference labels for the selection toolbar: a
|
|
3
|
-
*
|
|
4
|
-
* Pure derivation so the display rule is unit-testable without
|
|
2
|
+
* Reference labels for the selection toolbar: a workspace-relative path (or
|
|
3
|
+
* the absolute path when the file is outside the workspace) plus a 1-based
|
|
4
|
+
* line range. Pure derivation so the display rule is unit-testable without
|
|
5
|
+
* the panel.
|
|
5
6
|
* @module dsh-diff-approval/client/reference
|
|
6
7
|
*/
|
|
7
|
-
import type { PendingFileDiff } from '../types.ts';
|
|
8
8
|
/**
|
|
9
9
|
* Last path segment of a file path, any separator style.
|
|
10
10
|
* @param path - the path to shorten.
|
|
@@ -12,13 +12,15 @@ import type { PendingFileDiff } from '../types.ts';
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function basenameOf(path: string): string;
|
|
14
14
|
/**
|
|
15
|
-
* The path
|
|
16
|
-
* file
|
|
15
|
+
* The path embedded in a copied reference: workspace-relative (forward
|
|
16
|
+
* slashes) when the file lives inside the current workspace, the absolute
|
|
17
|
+
* path otherwise. A bare file name is never enough — a reference must resolve
|
|
18
|
+
* to exactly one file.
|
|
17
19
|
* @param path - the selected file's path.
|
|
18
|
-
* @param
|
|
19
|
-
* @returns the
|
|
20
|
+
* @param workspacePath - the current workspace root, or `undefined`.
|
|
21
|
+
* @returns the reference path.
|
|
20
22
|
*/
|
|
21
|
-
export declare function
|
|
23
|
+
export declare function referencePathOf(path: string, workspacePath: string | undefined): string;
|
|
22
24
|
/**
|
|
23
25
|
* Format one line range as a reference suffix: a single line number, or the
|
|
24
26
|
* inclusive range when the selection spans more than one line.
|
|
@@ -30,9 +32,9 @@ export declare function lineRangeLabel(start: number, end: number): string;
|
|
|
30
32
|
/**
|
|
31
33
|
* Build the clipboard text for a selected line range.
|
|
32
34
|
* @param path - the selected file's path.
|
|
33
|
-
* @param
|
|
35
|
+
* @param workspacePath - the current workspace root, or `undefined`.
|
|
34
36
|
* @param start - first selected line number.
|
|
35
37
|
* @param end - last selected line number.
|
|
36
38
|
* @returns the `path:range` reference text.
|
|
37
39
|
*/
|
|
38
|
-
export declare function referenceOf(path: string,
|
|
40
|
+
export declare function referenceOf(path: string, workspacePath: string | undefined, start: number, end: number): string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** The panel's injected business face and its observable snapshot. */
|
|
2
2
|
import type { HostObservable } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
3
|
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client';
|
|
4
|
-
import type { DiffApprovalOpenAction, PendingFileDiff } from '../types.ts';
|
|
4
|
+
import type { DiffApprovalBlockRange, DiffApprovalOpenAction, PendingFileDiff } from '../types.ts';
|
|
5
5
|
/** What the panel reads and drives: the pending list plus in-flight entries. */
|
|
6
6
|
export interface PendingDiffSnapshot {
|
|
7
7
|
/** Whether a list read has completed at least once. */
|
|
@@ -12,6 +12,8 @@ export interface PendingDiffSnapshot {
|
|
|
12
12
|
error?: string;
|
|
13
13
|
/** Entry ids whose keep/revert is in flight; their controls are disabled. */
|
|
14
14
|
busy: ReadonlySet<string>;
|
|
15
|
+
/** The viewing session's workspace root (when it has one); enables workspace-relative references. */
|
|
16
|
+
workspacePath?: string | undefined;
|
|
15
17
|
}
|
|
16
18
|
/** The injected face the panel component receives from the plugin body. */
|
|
17
19
|
export interface PendingPanelFace {
|
|
@@ -25,6 +27,10 @@ export interface PendingPanelFace {
|
|
|
25
27
|
onKeep: (sessionId: SessionId, id: string) => Promise<void>;
|
|
26
28
|
/** Revert one operation (restore its prior content, or remove a created file). */
|
|
27
29
|
onRevert: (sessionId: SessionId, id: string) => Promise<void>;
|
|
30
|
+
/** Keep one diff block (accept its change into the tracked baseline). */
|
|
31
|
+
onBlockKeep: (sessionId: SessionId, id: string, block: DiffApprovalBlockRange) => Promise<void>;
|
|
32
|
+
/** Revert one diff block (restore its old lines in the file). */
|
|
33
|
+
onBlockRevert: (sessionId: SessionId, id: string, block: DiffApprovalBlockRange) => Promise<void>;
|
|
28
34
|
/** Open one file with its default application or reveal it in the folder. */
|
|
29
35
|
onOpen: (sessionId: SessionId, id: string, action: DiffApprovalOpenAction) => Promise<void>;
|
|
30
36
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { SessionId } from '@deepseek-ai/dsh-client-connection/client';
|
|
9
9
|
import type { HostObservable } from '@deepseek-ai/dsh-client-ui-slots';
|
|
10
|
-
import type { DiffApprovalOpenAction } from '../types.ts';
|
|
10
|
+
import type { DiffApprovalBlockRange, DiffApprovalOpenAction } from '../types.ts';
|
|
11
11
|
import type { PendingDiffSnapshot } from './slots.ts';
|
|
12
12
|
import type { DiffApprovalPort } from './port.ts';
|
|
13
13
|
/** The observable the panel reads and the plugin body drives. */
|
|
@@ -18,6 +18,10 @@ export interface PendingDiffStore extends HostObservable<PendingDiffSnapshot> {
|
|
|
18
18
|
keep: (sessionId: SessionId, id: string) => Promise<void>;
|
|
19
19
|
/** Revert one operation. */
|
|
20
20
|
revert: (sessionId: SessionId, id: string) => Promise<void>;
|
|
21
|
+
/** Keep one diff block, then refresh so the entry's diff reflects the accept. */
|
|
22
|
+
blockKeep: (sessionId: SessionId, id: string, block: DiffApprovalBlockRange) => Promise<void>;
|
|
23
|
+
/** Revert one diff block, then refresh so the entry's diff reflects the undo. */
|
|
24
|
+
blockRevert: (sessionId: SessionId, id: string, block: DiffApprovalBlockRange) => Promise<void>;
|
|
21
25
|
/** Open one file with its default application or reveal it in the folder. */
|
|
22
26
|
open: (sessionId: SessionId, id: string, action: DiffApprovalOpenAction) => Promise<void>;
|
|
23
27
|
/** Drop every local fact (used on connection reset). */
|
package/lib/types/index.d.ts
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
*/
|
|
36
36
|
import { Context } from '@deepseek-ai/cordis';
|
|
37
37
|
import type { DiffApprovalOpenAction } from './types.ts';
|
|
38
|
-
export type { DiffApprovalActionOutcome, DiffApprovalActionValue, DiffApprovalListValue, DiffApprovalOpenAction, DiffApprovalOpenValue, PendingEntry, PendingEntryKind, PendingFileDiff, } from './types.ts';
|
|
38
|
+
export type { DiffApprovalActionOutcome, DiffApprovalActionValue, DiffApprovalBlockRange, DiffApprovalBlockTarget, DiffApprovalListValue, DiffApprovalOpenAction, DiffApprovalOpenValue, PendingEntry, PendingEntryKind, PendingFileDiff, } from './types.ts';
|
|
39
39
|
export { PendingDiffStore } from './pending.ts';
|
|
40
40
|
export { PendingPersistence, defaultStorageDir } from './persist.ts';
|
|
41
41
|
export { defaultOpenPath } from './open.ts';
|
package/lib/types/pending.d.ts
CHANGED
|
@@ -55,6 +55,20 @@ export declare class PendingDiffStore {
|
|
|
55
55
|
* @returns whether an entry was removed.
|
|
56
56
|
*/
|
|
57
57
|
remove(sessionId: SessionId, id: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Advance one entry's tracked content after a block-level keep/revert. The
|
|
60
|
+
* entry keeps its id and path; only the given side's text and capture time
|
|
61
|
+
* move. When the caller decides the sides now match, it removes the entry
|
|
62
|
+
* instead of updating it.
|
|
63
|
+
* @param sessionId - the owning session.
|
|
64
|
+
* @param id - the entry id.
|
|
65
|
+
* @param patch - the side to advance (`oldText` for keep, `newText` for revert).
|
|
66
|
+
* @returns whether the entry changed.
|
|
67
|
+
*/
|
|
68
|
+
update(sessionId: SessionId, id: string, patch: {
|
|
69
|
+
oldText?: string;
|
|
70
|
+
newText?: string;
|
|
71
|
+
}): boolean;
|
|
58
72
|
/** Total entry count across all sessions. */
|
|
59
73
|
get size(): number;
|
|
60
74
|
}
|
package/lib/types/types.d.ts
CHANGED
|
@@ -51,6 +51,8 @@ export interface PendingFileDiff extends PendingEntry {
|
|
|
51
51
|
export interface DiffApprovalListValue {
|
|
52
52
|
/** Pending entries for the requested session, oldest capture first. */
|
|
53
53
|
files: PendingFileDiff[];
|
|
54
|
+
/** The viewing session's workspace root (when it has one), for workspace-relative references. */
|
|
55
|
+
workspacePath?: string | undefined;
|
|
54
56
|
}
|
|
55
57
|
/** What the open endpoint asks the OS to do with a file. */
|
|
56
58
|
export type DiffApprovalOpenAction = 'open' | 'reveal';
|
|
@@ -59,6 +61,27 @@ export interface DiffApprovalOpenValue {
|
|
|
59
61
|
/** What the request did; `missing` means no pending entry existed. */
|
|
60
62
|
outcome: 'opened' | 'missing';
|
|
61
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* One diff block's line ranges on the old and new sides, 1-based inclusive.
|
|
66
|
+
* A side is empty when its start exceeds its end; an empty side's start is
|
|
67
|
+
* the insertion point (the line before which content inserts) on that side.
|
|
68
|
+
*/
|
|
69
|
+
export interface DiffApprovalBlockRange {
|
|
70
|
+
/** First old-file line this block spans; the insertion point for pure additions. */
|
|
71
|
+
oldStart: number;
|
|
72
|
+
/** Last old-file line; `oldStart - 1` when the block has no old side. */
|
|
73
|
+
oldEnd: number;
|
|
74
|
+
/** First new-file line this block spans; the insertion point for pure deletions. */
|
|
75
|
+
newStart: number;
|
|
76
|
+
/** Last new-file line; `newStart - 1` when the block has no new side. */
|
|
77
|
+
newEnd: number;
|
|
78
|
+
}
|
|
79
|
+
/** Target of one block-level keep/revert: the entry plus the block range. */
|
|
80
|
+
export interface DiffApprovalBlockTarget {
|
|
81
|
+
sessionId: SessionId;
|
|
82
|
+
id: string;
|
|
83
|
+
block: DiffApprovalBlockRange;
|
|
84
|
+
}
|
|
62
85
|
/** Outcome of one keep/revert request. */
|
|
63
86
|
export type DiffApprovalActionOutcome = 'kept' | 'reverted' | 'missing';
|
|
64
87
|
/** Value returned by the channel's keep and revert endpoints. */
|
package/package.json
CHANGED