@norman-else/dsh-claude 0.1.32 → 0.1.33
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/INSTALL.md +1 -1
- package/README.md +1 -1
- package/lib/bin.mjs +1 -1
- package/lib/client.d.ts +25 -2
- package/lib/client.js +1299 -306
- package/lib/client.js.map +1 -1
- package/lib/{command-bridge-tqsu15hR.mjs → command-bridge-DXI6nWhB.mjs} +2 -2
- package/lib/{command-bridge-tqsu15hR.mjs.map → command-bridge-DXI6nWhB.mjs.map} +1 -1
- package/lib/{events-CSDcXsWE.mjs → events-DeSV0S1-.mjs} +3 -2
- package/lib/events-DeSV0S1-.mjs.map +1 -0
- package/lib/index.mjs +415 -101
- package/lib/index.mjs.map +1 -1
- package/lib/{preset-installer-CVdbU87E.mjs → preset-installer-DbmlhBXI.mjs} +9 -11
- package/lib/preset-installer-DbmlhBXI.mjs.map +1 -0
- package/lib/preset-route.mjs +2 -2
- package/package.json +188 -184
- package/lib/events-CSDcXsWE.mjs.map +0 -1
- package/lib/preset-installer-CVdbU87E.mjs.map +0 -1
package/lib/client.js
CHANGED
|
@@ -4,13 +4,14 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
module.exports;
|
|
6
6
|
var { Fragment, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } = require("react");
|
|
7
|
-
var { DiffBlock, DisclosureRow, HoverCard, IconAgentPresetOutline16, IconApiOutline14, IconBranchOutline16, IconCheckOutline14, IconCheckOutline16, IconChevronDownOutline14, IconChevronRightOutline14, IconChevronUpOutline14, IconCloseOutline16, IconEditOutline16, IconEllipsisOutline16, IconFullscreenOutline16, IconQueueOutline14, IconRefreshOutline14, IconSearchOutline16, IconSendOutline14, IconThinkOutline14, IconTrashOutline16, MarkdownText, Menu, Modal, StateDot, Tooltip, useDismissOnOutsidePointer } = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
7
|
+
var { DiffBlock, DisclosureRow, HoverCard, IconAgentPresetOutline16, IconApiOutline14, IconBranchOutline16, IconCheckOutline14, IconCheckOutline16, IconChevronDownOutline14, IconChevronRightOutline14, IconChevronUpOutline14, IconCloseOutline16, IconEditOutline16, IconEllipsisOutline16, IconFullscreenOutline16, IconQueueOutline14, IconRefreshOutline14, IconRightUpOutline14, IconSearchOutline16, IconSendOutline14, IconThinkOutline14, IconTrashOutline16, MarkdownText, Menu, Modal, StateDot, Toast, Tooltip, useDismissOnOutsidePointer } = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
8
8
|
var { Fragment: Fragment$1, jsx, jsxs } = require("react/jsx-runtime");
|
|
9
9
|
var { createPortal } = require("react-dom");
|
|
10
10
|
/** Claude's subagent dispatch tools; rendered as plugin-owned group cards
|
|
11
11
|
* gathering subagent activity instead of native tool cards. */
|
|
12
12
|
const TASK_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
|
|
13
13
|
const CLAUDE_DOCTOR_PATH = "/plugins/dsh-claude/doctor";
|
|
14
|
+
const CLAUDE_CLIENT_DIAGNOSTICS_PATH = "/plugins/dsh-claude/client-diagnostics";
|
|
14
15
|
const CLAUDE_UPDATE_CHECK_PATH = "/plugins/dsh-claude/update/check";
|
|
15
16
|
const CLAUDE_USAGE_PATH = "/plugins/dsh-claude/usage";
|
|
16
17
|
const CLAUDE_UPDATE_PATH = "/plugins/dsh-claude/update";
|
|
@@ -1551,7 +1552,7 @@ window.__ModuleLoader__.load({
|
|
|
1551
1552
|
};
|
|
1552
1553
|
const repositoryBarFrame = {
|
|
1553
1554
|
width: "calc(100% - 64px)",
|
|
1554
|
-
maxWidth: "var(--dsh-
|
|
1555
|
+
maxWidth: "var(--dsh-composer-card-max-width, 782px)",
|
|
1555
1556
|
minWidth: 0,
|
|
1556
1557
|
margin: "0 auto",
|
|
1557
1558
|
boxSizing: "border-box"
|
|
@@ -2063,9 +2064,11 @@ window.__ModuleLoader__.load({
|
|
|
2063
2064
|
fontWeight: 600
|
|
2064
2065
|
};
|
|
2065
2066
|
const diffGhCommentLink = {
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2067
|
+
display: "inline-flex",
|
|
2068
|
+
alignItems: "center",
|
|
2069
|
+
flex: "none",
|
|
2070
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2071
|
+
textDecoration: "none"
|
|
2069
2072
|
};
|
|
2070
2073
|
const diffModalConflicts = {
|
|
2071
2074
|
display: "flex",
|
|
@@ -2538,6 +2541,156 @@ window.__ModuleLoader__.load({
|
|
|
2538
2541
|
font: "inherit",
|
|
2539
2542
|
resize: "vertical"
|
|
2540
2543
|
};
|
|
2544
|
+
const diffGhComment = {
|
|
2545
|
+
display: "flex",
|
|
2546
|
+
flexDirection: "column",
|
|
2547
|
+
gap: 4
|
|
2548
|
+
};
|
|
2549
|
+
/** Every comment after the first opens with a rule, the way GitHub separates
|
|
2550
|
+
* the entries of one conversation. */
|
|
2551
|
+
const diffGhCommentNext = {
|
|
2552
|
+
marginTop: 8,
|
|
2553
|
+
paddingTop: 8,
|
|
2554
|
+
borderTop: "1px solid var(--dsw-alias-border-l1, color-mix(in srgb, currentColor 12%, transparent))"
|
|
2555
|
+
};
|
|
2556
|
+
const diffGhCommentAge = {
|
|
2557
|
+
flex: "none",
|
|
2558
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2559
|
+
fontSize: 11
|
|
2560
|
+
};
|
|
2561
|
+
/** Big enough to aim at: the 11px "›" glyph was a hard target. */
|
|
2562
|
+
const diffFileChevron = {
|
|
2563
|
+
width: 14,
|
|
2564
|
+
height: 14,
|
|
2565
|
+
display: "inline-flex",
|
|
2566
|
+
alignItems: "center",
|
|
2567
|
+
justifyContent: "center",
|
|
2568
|
+
flex: "none",
|
|
2569
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
2570
|
+
transition: "transform 120ms ease"
|
|
2571
|
+
};
|
|
2572
|
+
const diffSummaryAction = {
|
|
2573
|
+
marginLeft: "auto",
|
|
2574
|
+
padding: "2px 8px",
|
|
2575
|
+
border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
|
|
2576
|
+
borderRadius: 6,
|
|
2577
|
+
background: "transparent",
|
|
2578
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
2579
|
+
font: "inherit",
|
|
2580
|
+
fontSize: 12,
|
|
2581
|
+
cursor: "pointer"
|
|
2582
|
+
};
|
|
2583
|
+
const diffCommentNav = {
|
|
2584
|
+
display: "inline-flex",
|
|
2585
|
+
alignItems: "center",
|
|
2586
|
+
gap: 2
|
|
2587
|
+
};
|
|
2588
|
+
const diffCommentNavCount = {
|
|
2589
|
+
minWidth: 34,
|
|
2590
|
+
textAlign: "center",
|
|
2591
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2592
|
+
fontSize: 12,
|
|
2593
|
+
fontVariantNumeric: "tabular-nums"
|
|
2594
|
+
};
|
|
2595
|
+
/** Where the walk stopped, so the eye lands without hunting for it. */
|
|
2596
|
+
const diffCommentBlockActive = {
|
|
2597
|
+
borderColor: "var(--dsw-static-blue-450)",
|
|
2598
|
+
boxShadow: "0 0 0 1px var(--dsw-static-blue-450)"
|
|
2599
|
+
};
|
|
2600
|
+
const diffThreadBadges = {
|
|
2601
|
+
display: "flex",
|
|
2602
|
+
gap: 6
|
|
2603
|
+
};
|
|
2604
|
+
const diffThreadBadge = {
|
|
2605
|
+
flex: "none",
|
|
2606
|
+
padding: "0 6px",
|
|
2607
|
+
borderRadius: 999,
|
|
2608
|
+
background: "var(--dsw-alias-bg-layer-2)",
|
|
2609
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2610
|
+
fontSize: 11,
|
|
2611
|
+
lineHeight: "18px"
|
|
2612
|
+
};
|
|
2613
|
+
const diffThreadSummary = {
|
|
2614
|
+
width: "100%",
|
|
2615
|
+
display: "flex",
|
|
2616
|
+
alignItems: "center",
|
|
2617
|
+
gap: 6,
|
|
2618
|
+
minWidth: 0,
|
|
2619
|
+
padding: 0,
|
|
2620
|
+
border: "none",
|
|
2621
|
+
background: "transparent",
|
|
2622
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2623
|
+
font: "inherit",
|
|
2624
|
+
fontSize: 12,
|
|
2625
|
+
textAlign: "left",
|
|
2626
|
+
cursor: "pointer"
|
|
2627
|
+
};
|
|
2628
|
+
const diffThreadExcerpt = {
|
|
2629
|
+
minWidth: 0,
|
|
2630
|
+
flex: 1,
|
|
2631
|
+
overflow: "hidden",
|
|
2632
|
+
textOverflow: "ellipsis",
|
|
2633
|
+
whiteSpace: "nowrap"
|
|
2634
|
+
};
|
|
2635
|
+
/** The composer is a region of its own: without the rule it reads as more of
|
|
2636
|
+
* the comment it sits under. */
|
|
2637
|
+
const diffThreadComposer = {
|
|
2638
|
+
display: "flex",
|
|
2639
|
+
flexDirection: "column",
|
|
2640
|
+
gap: 6,
|
|
2641
|
+
marginTop: 10,
|
|
2642
|
+
paddingTop: 10,
|
|
2643
|
+
borderTop: "1px solid var(--dsw-alias-border-l1, color-mix(in srgb, currentColor 12%, transparent))"
|
|
2644
|
+
};
|
|
2645
|
+
const diffThreadComposerCaption = {
|
|
2646
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
2647
|
+
fontSize: 11,
|
|
2648
|
+
lineHeight: "16px"
|
|
2649
|
+
};
|
|
2650
|
+
const mentionField = {
|
|
2651
|
+
position: "relative",
|
|
2652
|
+
display: "block"
|
|
2653
|
+
};
|
|
2654
|
+
const mentionList = {
|
|
2655
|
+
position: "absolute",
|
|
2656
|
+
zIndex: 1100,
|
|
2657
|
+
top: "100%",
|
|
2658
|
+
left: 0,
|
|
2659
|
+
width: 240,
|
|
2660
|
+
maxHeight: 176,
|
|
2661
|
+
boxSizing: "border-box",
|
|
2662
|
+
display: "flex",
|
|
2663
|
+
flexDirection: "column",
|
|
2664
|
+
gap: 2,
|
|
2665
|
+
padding: 4,
|
|
2666
|
+
overflowY: "auto",
|
|
2667
|
+
border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
|
|
2668
|
+
borderRadius: 8,
|
|
2669
|
+
background: "var(--dsw-specific-menu)",
|
|
2670
|
+
boxShadow: "var(--dsw-shadow-lv3)"
|
|
2671
|
+
};
|
|
2672
|
+
const mentionItem = {
|
|
2673
|
+
height: 28,
|
|
2674
|
+
display: "flex",
|
|
2675
|
+
alignItems: "center",
|
|
2676
|
+
gap: 6,
|
|
2677
|
+
padding: "0 8px",
|
|
2678
|
+
border: "none",
|
|
2679
|
+
borderRadius: 6,
|
|
2680
|
+
background: "transparent",
|
|
2681
|
+
color: "var(--dsw-alias-label-primary)",
|
|
2682
|
+
font: "inherit",
|
|
2683
|
+
fontSize: 13,
|
|
2684
|
+
textAlign: "left",
|
|
2685
|
+
cursor: "pointer"
|
|
2686
|
+
};
|
|
2687
|
+
const mentionItemActive = { background: "var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2))" };
|
|
2688
|
+
const mentionAvatar = {
|
|
2689
|
+
width: 16,
|
|
2690
|
+
height: 16,
|
|
2691
|
+
flex: "none",
|
|
2692
|
+
borderRadius: "50%"
|
|
2693
|
+
};
|
|
2541
2694
|
const diffCommentActions = {
|
|
2542
2695
|
display: "flex",
|
|
2543
2696
|
justifyContent: "flex-end",
|
|
@@ -2568,7 +2721,7 @@ window.__ModuleLoader__.load({
|
|
|
2568
2721
|
};
|
|
2569
2722
|
const reviewCommentBarFrame = {
|
|
2570
2723
|
width: "calc(100% - 64px)",
|
|
2571
|
-
maxWidth: "var(--dsh-
|
|
2724
|
+
maxWidth: "var(--dsh-composer-card-max-width, 782px)",
|
|
2572
2725
|
margin: "0 auto",
|
|
2573
2726
|
boxSizing: "border-box"
|
|
2574
2727
|
};
|
|
@@ -2987,12 +3140,12 @@ window.__ModuleLoader__.load({
|
|
|
2987
3140
|
background: var(--dsw-alias-bg-layer-2);
|
|
2988
3141
|
}
|
|
2989
3142
|
.dshClaudeRepositoryActionModalContent h2 {
|
|
2990
|
-
font-size:
|
|
2991
|
-
line-height:
|
|
3143
|
+
font-size: 16px;
|
|
3144
|
+
line-height: 24px;
|
|
2992
3145
|
}
|
|
2993
3146
|
.dshClaudeRepositoryActionModalContent > p {
|
|
2994
|
-
font-size:
|
|
2995
|
-
line-height:
|
|
3147
|
+
font-size: 13px;
|
|
3148
|
+
line-height: 20px;
|
|
2996
3149
|
}
|
|
2997
3150
|
.dshClaudeRepositoryActionModal input:is([type='checkbox'], [type='radio']) {
|
|
2998
3151
|
width: 16px;
|
|
@@ -3009,7 +3162,7 @@ window.__ModuleLoader__.load({
|
|
|
3009
3162
|
const diffModalBody = {
|
|
3010
3163
|
display: "flex",
|
|
3011
3164
|
flexDirection: "column",
|
|
3012
|
-
gap:
|
|
3165
|
+
gap: 14,
|
|
3013
3166
|
width: "100%",
|
|
3014
3167
|
minWidth: 0,
|
|
3015
3168
|
boxSizing: "border-box"
|
|
@@ -3020,8 +3173,8 @@ window.__ModuleLoader__.load({
|
|
|
3020
3173
|
gap: 16,
|
|
3021
3174
|
minWidth: 0,
|
|
3022
3175
|
color: "var(--dsw-alias-label-secondary)",
|
|
3023
|
-
fontSize:
|
|
3024
|
-
lineHeight: "
|
|
3176
|
+
fontSize: 13,
|
|
3177
|
+
lineHeight: "20px"
|
|
3025
3178
|
};
|
|
3026
3179
|
const diffModalMetaText = {
|
|
3027
3180
|
minWidth: 0,
|
|
@@ -3042,11 +3195,11 @@ window.__ModuleLoader__.load({
|
|
|
3042
3195
|
justifyContent: "space-between",
|
|
3043
3196
|
gap: 12,
|
|
3044
3197
|
minWidth: 0,
|
|
3045
|
-
padding: "
|
|
3198
|
+
padding: "8px 12px",
|
|
3046
3199
|
borderBottom: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
|
|
3047
3200
|
color: "var(--dsw-alias-label-secondary)",
|
|
3048
|
-
fontSize:
|
|
3049
|
-
lineHeight: "
|
|
3201
|
+
fontSize: 12,
|
|
3202
|
+
lineHeight: "18px"
|
|
3050
3203
|
};
|
|
3051
3204
|
const diffModalFilePath = {
|
|
3052
3205
|
minWidth: 0,
|
|
@@ -3058,34 +3211,34 @@ window.__ModuleLoader__.load({
|
|
|
3058
3211
|
const diffModalField = {
|
|
3059
3212
|
display: "flex",
|
|
3060
3213
|
flexDirection: "column",
|
|
3061
|
-
gap:
|
|
3214
|
+
gap: 6,
|
|
3062
3215
|
color: "var(--dsw-alias-label-secondary)",
|
|
3063
|
-
fontSize:
|
|
3064
|
-
lineHeight: "
|
|
3216
|
+
fontSize: 12,
|
|
3217
|
+
lineHeight: "18px",
|
|
3065
3218
|
fontWeight: 550
|
|
3066
3219
|
};
|
|
3067
3220
|
const diffModalTextarea = {
|
|
3068
3221
|
...settingTextInput,
|
|
3069
|
-
minHeight:
|
|
3070
|
-
padding: "
|
|
3071
|
-
fontSize:
|
|
3072
|
-
lineHeight: "
|
|
3222
|
+
minHeight: 120,
|
|
3223
|
+
padding: "9px 12px",
|
|
3224
|
+
fontSize: 13,
|
|
3225
|
+
lineHeight: "20px",
|
|
3073
3226
|
resize: "vertical"
|
|
3074
3227
|
};
|
|
3075
3228
|
const diffModalTextInput = {
|
|
3076
3229
|
...settingTextInput,
|
|
3077
|
-
minHeight:
|
|
3078
|
-
padding: "
|
|
3079
|
-
fontSize:
|
|
3080
|
-
lineHeight: "
|
|
3230
|
+
minHeight: 36,
|
|
3231
|
+
padding: "7px 12px",
|
|
3232
|
+
fontSize: 13,
|
|
3233
|
+
lineHeight: "20px"
|
|
3081
3234
|
};
|
|
3082
3235
|
const diffModalCheckbox = {
|
|
3083
3236
|
display: "flex",
|
|
3084
3237
|
alignItems: "center",
|
|
3085
|
-
gap:
|
|
3238
|
+
gap: 8,
|
|
3086
3239
|
color: "var(--dsw-alias-label-secondary)",
|
|
3087
|
-
fontSize:
|
|
3088
|
-
lineHeight: "
|
|
3240
|
+
fontSize: 13,
|
|
3241
|
+
lineHeight: "20px"
|
|
3089
3242
|
};
|
|
3090
3243
|
const diffModalFooter = {
|
|
3091
3244
|
display: "flex",
|
|
@@ -3093,28 +3246,22 @@ window.__ModuleLoader__.load({
|
|
|
3093
3246
|
gap: 12
|
|
3094
3247
|
};
|
|
3095
3248
|
const diffModalButton = {
|
|
3096
|
-
minHeight:
|
|
3097
|
-
padding: "
|
|
3098
|
-
fontSize:
|
|
3099
|
-
lineHeight: "
|
|
3249
|
+
minHeight: 34,
|
|
3250
|
+
padding: "6px 16px",
|
|
3251
|
+
fontSize: 13,
|
|
3252
|
+
lineHeight: "20px"
|
|
3100
3253
|
};
|
|
3101
3254
|
const diffModalStatus = {
|
|
3102
3255
|
margin: 0,
|
|
3103
3256
|
color: "var(--dsw-alias-label-secondary)",
|
|
3104
|
-
fontSize:
|
|
3105
|
-
lineHeight: "
|
|
3257
|
+
fontSize: 13,
|
|
3258
|
+
lineHeight: "20px"
|
|
3106
3259
|
};
|
|
3107
3260
|
const diffModalError = {
|
|
3108
|
-
margin: "
|
|
3261
|
+
margin: "8px 0 0",
|
|
3109
3262
|
color: "var(--dsw-alias-state-error-primary)",
|
|
3110
|
-
fontSize:
|
|
3111
|
-
lineHeight: "
|
|
3112
|
-
};
|
|
3113
|
-
const diffModalSuccess = {
|
|
3114
|
-
margin: 0,
|
|
3115
|
-
color: "var(--dsw-alias-state-success-primary)",
|
|
3116
|
-
fontSize: 14,
|
|
3117
|
-
lineHeight: "22px"
|
|
3263
|
+
fontSize: 13,
|
|
3264
|
+
lineHeight: "20px"
|
|
3118
3265
|
};
|
|
3119
3266
|
const rewindActionCss = `
|
|
3120
3267
|
[data-dsh-claude-rewind]:empty {
|
|
@@ -3589,6 +3736,32 @@ window.__ModuleLoader__.load({
|
|
|
3589
3736
|
});
|
|
3590
3737
|
}
|
|
3591
3738
|
//#endregion
|
|
3739
|
+
//#region src/client/markdown-labels.tsx
|
|
3740
|
+
/** Stable across renders: MarkdownText keys its streaming renderer on this
|
|
3741
|
+
* object's identity and reparses from scratch whenever it changes. */
|
|
3742
|
+
function useClaudeMarkdownLabels(t) {
|
|
3743
|
+
return useMemo(() => ({
|
|
3744
|
+
code: {
|
|
3745
|
+
copyLabel: t("markdownCopy"),
|
|
3746
|
+
copiedLabel: t("markdownCopied")
|
|
3747
|
+
},
|
|
3748
|
+
footnotes: t("markdownFootnotes")
|
|
3749
|
+
}), [t]);
|
|
3750
|
+
}
|
|
3751
|
+
/** MarkdownText with the labels the running Host demands.
|
|
3752
|
+
*
|
|
3753
|
+
* The published primitives package still types the old `codeLabels` prop, so
|
|
3754
|
+
* the new shape cannot typecheck against it — the cast is confined here rather
|
|
3755
|
+
* than repeated at every call site. Drop it once the installed
|
|
3756
|
+
* @deepseek-ai/dsh-client-ui-primitives matches the Desktop build. */
|
|
3757
|
+
function ClaudeMarkdown({ text, labels, streaming }) {
|
|
3758
|
+
return /* @__PURE__ */ jsx(MarkdownText, {
|
|
3759
|
+
text,
|
|
3760
|
+
labels,
|
|
3761
|
+
...streaming === void 0 ? {} : { streaming }
|
|
3762
|
+
});
|
|
3763
|
+
}
|
|
3764
|
+
//#endregion
|
|
3592
3765
|
//#region src/rewind.ts
|
|
3593
3766
|
function isRewound(ranges, seq) {
|
|
3594
3767
|
return ranges.some((range) => seq >= range.start && seq <= range.end);
|
|
@@ -4429,12 +4602,16 @@ window.__ModuleLoader__.load({
|
|
|
4429
4602
|
marker.turn,
|
|
4430
4603
|
tasks
|
|
4431
4604
|
]);
|
|
4605
|
+
const markdownLabels = useClaudeMarkdownLabels(t);
|
|
4432
4606
|
if (items.length === 0) return null;
|
|
4433
4607
|
return /* @__PURE__ */ jsx("div", {
|
|
4434
4608
|
className: "dsh-claude-flow",
|
|
4435
4609
|
children: items.map((item) => item.kind === "text" ? /* @__PURE__ */ jsx("div", {
|
|
4436
4610
|
className: "dsh-claude-transcript-text",
|
|
4437
|
-
children: /* @__PURE__ */ jsx(
|
|
4611
|
+
children: /* @__PURE__ */ jsx(ClaudeMarkdown, {
|
|
4612
|
+
text: item.text,
|
|
4613
|
+
labels: markdownLabels
|
|
4614
|
+
})
|
|
4438
4615
|
}, `text:${item.ordinal}`) : item.kind === "compaction" ? /* @__PURE__ */ jsx(ClaudeCompactionDivider, {
|
|
4439
4616
|
compaction: item.compaction,
|
|
4440
4617
|
t
|
|
@@ -5486,6 +5663,36 @@ window.__ModuleLoader__.load({
|
|
|
5486
5663
|
})).then(result);
|
|
5487
5664
|
}
|
|
5488
5665
|
//#endregion
|
|
5666
|
+
//#region src/client/action-toast.tsx
|
|
5667
|
+
/** Always a new id, even for the same text: the id is the Toast's key, and
|
|
5668
|
+
* reporting the same outcome twice has to replay the banner rather than
|
|
5669
|
+
* update the text of one that is already fading out. */
|
|
5670
|
+
function nextActionToast(current, text) {
|
|
5671
|
+
return {
|
|
5672
|
+
id: (current?.id ?? 0) + 1,
|
|
5673
|
+
text
|
|
5674
|
+
};
|
|
5675
|
+
}
|
|
5676
|
+
/** Report a finished Git action the way the Host reports everything else: a
|
|
5677
|
+
* banner over the window, not a line inside the dialog that asked for it. The
|
|
5678
|
+
* dialog closes the moment the work lands, so the notice has to outlive it. */
|
|
5679
|
+
function useActionToast() {
|
|
5680
|
+
const [shown, setShown] = useState();
|
|
5681
|
+
const done = useCallback(() => {
|
|
5682
|
+
setShown(void 0);
|
|
5683
|
+
}, []);
|
|
5684
|
+
const report = useCallback((text) => {
|
|
5685
|
+
setShown((current) => nextActionToast(current, text));
|
|
5686
|
+
}, []);
|
|
5687
|
+
return {
|
|
5688
|
+
toast: shown === void 0 ? null : /* @__PURE__ */ jsx(Toast, {
|
|
5689
|
+
text: shown.text,
|
|
5690
|
+
onDone: done
|
|
5691
|
+
}, shown.id),
|
|
5692
|
+
report
|
|
5693
|
+
};
|
|
5694
|
+
}
|
|
5695
|
+
//#endregion
|
|
5489
5696
|
//#region src/client/repository-setup-api.ts
|
|
5490
5697
|
const HOST_STAGES = /* @__PURE__ */ new Set([
|
|
5491
5698
|
"inspecting",
|
|
@@ -5657,6 +5864,20 @@ window.__ModuleLoader__.load({
|
|
|
5657
5864
|
return body;
|
|
5658
5865
|
}
|
|
5659
5866
|
//#endregion
|
|
5867
|
+
//#region src/client/relative-age.ts
|
|
5868
|
+
/** Compact age of an ISO timestamp, in the shape the panels already use
|
|
5869
|
+
* ("<1h", "4h", "3d", "2mo"). `now` is a parameter so callers that re-render
|
|
5870
|
+
* on a clock — and tests — stay deterministic. */
|
|
5871
|
+
function relativeAge(value, now = Date.now()) {
|
|
5872
|
+
if (value === void 0) return void 0;
|
|
5873
|
+
const elapsedHours = Math.max(0, Math.floor((now - Date.parse(value)) / 36e5));
|
|
5874
|
+
if (!Number.isFinite(elapsedHours)) return void 0;
|
|
5875
|
+
if (elapsedHours < 1) return "<1h";
|
|
5876
|
+
if (elapsedHours < 24) return `${elapsedHours}h`;
|
|
5877
|
+
const days = Math.floor(elapsedHours / 24);
|
|
5878
|
+
return days < 30 ? `${days}d` : `${Math.floor(days / 30)}mo`;
|
|
5879
|
+
}
|
|
5880
|
+
//#endregion
|
|
5660
5881
|
//#region src/github-url.ts
|
|
5661
5882
|
/** Only GitHub's own image hosts; the browser loads these directly, so a URL
|
|
5662
5883
|
* the API did not vouch for must never become an outbound request. */
|
|
@@ -5675,28 +5896,95 @@ window.__ModuleLoader__.load({
|
|
|
5675
5896
|
function record$2(value) {
|
|
5676
5897
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
5677
5898
|
}
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
headers: { accept: "application/json" },
|
|
5683
|
-
signal: pluginRequestSignal(PLUGIN_READ_TIMEOUT_MS, signal)
|
|
5684
|
-
});
|
|
5899
|
+
function feedbackUrl(path, sessionId, pullNumber, extra = "") {
|
|
5900
|
+
return `${CLAUDE_REPOSITORY_FEEDBACK_PATH}${path}?sessionId=${encodeURIComponent(sessionId)}&number=${pullNumber}${extra}`;
|
|
5901
|
+
}
|
|
5902
|
+
async function answer(response) {
|
|
5685
5903
|
const body = record$2(await response.json());
|
|
5686
5904
|
if (!response.ok) throw new Error(typeof body?.message === "string" ? body.message : "Pull request feedback is unavailable.");
|
|
5687
5905
|
if (body === void 0) throw new Error("Invalid pull request feedback response.");
|
|
5688
5906
|
return body;
|
|
5689
5907
|
}
|
|
5690
|
-
async function
|
|
5908
|
+
async function loadJson(path, sessionId, pullNumber, signal, extra = "") {
|
|
5909
|
+
return answer(await fetch(feedbackUrl(path, sessionId, pullNumber, extra), {
|
|
5910
|
+
method: "GET",
|
|
5911
|
+
credentials: "same-origin",
|
|
5912
|
+
headers: { accept: "application/json" },
|
|
5913
|
+
signal: pluginRequestSignal(PLUGIN_READ_TIMEOUT_MS, signal)
|
|
5914
|
+
}));
|
|
5915
|
+
}
|
|
5916
|
+
/** Writes reach GitHub through `gh`, so they get the action deadline. */
|
|
5917
|
+
async function postJson(path, sessionId, pullNumber, input) {
|
|
5918
|
+
return answer(await fetch(feedbackUrl(path, sessionId, pullNumber), {
|
|
5919
|
+
method: "POST",
|
|
5920
|
+
credentials: "same-origin",
|
|
5921
|
+
headers: {
|
|
5922
|
+
accept: "application/json",
|
|
5923
|
+
"content-type": "application/json"
|
|
5924
|
+
},
|
|
5925
|
+
signal: pluginRequestSignal(PLUGIN_ACTION_TIMEOUT_MS),
|
|
5926
|
+
body: JSON.stringify(input)
|
|
5927
|
+
}));
|
|
5928
|
+
}
|
|
5929
|
+
function reviewComment(value) {
|
|
5930
|
+
const input = record$2(value);
|
|
5931
|
+
if (input === void 0 || typeof input.id !== "number" || typeof input.path !== "string" || typeof input.author !== "string" || typeof input.body !== "string" || typeof input.url !== "string" || input.avatarUrl !== void 0 && githubAvatarUrl(input.avatarUrl) === void 0 || input.side !== "new" && input.side !== "old" || input.line !== void 0 && typeof input.line !== "number" || input.createdAt !== void 0 && typeof input.createdAt !== "string" || input.bot !== void 0 && typeof input.bot !== "boolean") return void 0;
|
|
5932
|
+
return input;
|
|
5933
|
+
}
|
|
5934
|
+
async function loadPullRequestThreads(sessionId, pullNumber, signal) {
|
|
5691
5935
|
const body = await loadJson("/comments", sessionId, pullNumber, signal);
|
|
5692
|
-
if (!Array.isArray(body.
|
|
5693
|
-
const
|
|
5694
|
-
for (const item of body.
|
|
5936
|
+
if (!Array.isArray(body.threads)) throw new Error("Invalid pull request comments response.");
|
|
5937
|
+
const threads = [];
|
|
5938
|
+
for (const item of body.threads) {
|
|
5695
5939
|
const input = record$2(item);
|
|
5696
|
-
if (input === void 0 || typeof input.id !== "
|
|
5697
|
-
comments.
|
|
5940
|
+
if (input === void 0 || typeof input.id !== "string" || typeof input.path !== "string" || input.side !== "new" && input.side !== "old" || input.line !== void 0 && typeof input.line !== "number" || !Array.isArray(input.comments)) continue;
|
|
5941
|
+
const comments = input.comments.map(reviewComment).filter((value) => value !== void 0);
|
|
5942
|
+
if (comments.length === 0) continue;
|
|
5943
|
+
threads.push({
|
|
5944
|
+
id: input.id,
|
|
5945
|
+
path: input.path,
|
|
5946
|
+
...typeof input.line === "number" ? { line: input.line } : {},
|
|
5947
|
+
side: input.side,
|
|
5948
|
+
resolved: input.resolved === true,
|
|
5949
|
+
outdated: input.outdated === true,
|
|
5950
|
+
comments
|
|
5951
|
+
});
|
|
5952
|
+
}
|
|
5953
|
+
return threads;
|
|
5954
|
+
}
|
|
5955
|
+
/** Post one reply into the thread that `commentId` belongs to. */
|
|
5956
|
+
async function replyToReviewThread(sessionId, pullNumber, commentId, body) {
|
|
5957
|
+
const comment = reviewComment((await postJson("/reply", sessionId, pullNumber, {
|
|
5958
|
+
commentId,
|
|
5959
|
+
body
|
|
5960
|
+
})).comment);
|
|
5961
|
+
if (comment === void 0) throw new Error("Invalid pull request reply response.");
|
|
5962
|
+
return comment;
|
|
5963
|
+
}
|
|
5964
|
+
/** Resolve or reopen a thread; returns the state GitHub reports afterwards. */
|
|
5965
|
+
async function setReviewThreadResolved(sessionId, pullNumber, threadId, resolved) {
|
|
5966
|
+
const answer = await postJson("/resolve", sessionId, pullNumber, {
|
|
5967
|
+
threadId,
|
|
5968
|
+
resolved
|
|
5969
|
+
});
|
|
5970
|
+
if (typeof answer.resolved !== "boolean") throw new Error("Invalid pull request resolve response.");
|
|
5971
|
+
return answer.resolved;
|
|
5972
|
+
}
|
|
5973
|
+
/** Logins GitHub would notify, for the reply composer's `@` completion. */
|
|
5974
|
+
async function loadMentionableUsers(sessionId, pullNumber, query, signal) {
|
|
5975
|
+
const body = await loadJson("/mentionables", sessionId, pullNumber, signal, `&q=${encodeURIComponent(query)}`);
|
|
5976
|
+
if (!Array.isArray(body.users)) return [];
|
|
5977
|
+
const users = [];
|
|
5978
|
+
for (const item of body.users) {
|
|
5979
|
+
const input = record$2(item);
|
|
5980
|
+
if (input === void 0 || typeof input.login !== "string" || input.login.length === 0) continue;
|
|
5981
|
+
const avatarUrl = githubAvatarUrl(input.avatarUrl);
|
|
5982
|
+
users.push({
|
|
5983
|
+
login: input.login,
|
|
5984
|
+
...avatarUrl === void 0 ? {} : { avatarUrl }
|
|
5985
|
+
});
|
|
5698
5986
|
}
|
|
5699
|
-
return
|
|
5987
|
+
return users;
|
|
5700
5988
|
}
|
|
5701
5989
|
async function loadFailingChecks(sessionId, pullNumber, signal) {
|
|
5702
5990
|
const body = await loadJson("/checks", sessionId, pullNumber, signal);
|
|
@@ -5709,9 +5997,17 @@ window.__ModuleLoader__.load({
|
|
|
5709
5997
|
}
|
|
5710
5998
|
return checks;
|
|
5711
5999
|
}
|
|
5712
|
-
/** Draft handed to Claude when the user forwards GitHub review comments.
|
|
5713
|
-
|
|
5714
|
-
|
|
6000
|
+
/** Draft handed to Claude when the user forwards GitHub review comments. A
|
|
6001
|
+
* resolved thread is a settled conversation: forwarding it would ask Claude to
|
|
6002
|
+
* redo work the reviewers already signed off. */
|
|
6003
|
+
function composeCommentsPrompt(threads) {
|
|
6004
|
+
const open = threads.filter((thread) => !thread.resolved);
|
|
6005
|
+
if (open.length === 0) return "";
|
|
6006
|
+
return `Please address the following GitHub pull request review comments. Make the requested changes, or explain briefly when a comment should not be applied.\n\n${open.map((thread) => {
|
|
6007
|
+
const [first, ...rest] = thread.comments;
|
|
6008
|
+
if (first === void 0) return "";
|
|
6009
|
+
return [`- ${`${thread.path}${thread.line === void 0 ? "" : `:${thread.line}`}`} (@${first.author}): ${first.body.replaceAll("\n", "\n ")}`, ...rest.map((reply) => ` (@${reply.author}): ${reply.body.replaceAll("\n", "\n ")}`)].join("\n");
|
|
6010
|
+
}).filter((block) => block.length > 0).join("\n")}`;
|
|
5715
6011
|
}
|
|
5716
6012
|
/** Draft handed to Claude when the user forwards failing CI checks. */
|
|
5717
6013
|
function composeChecksPrompt(checks) {
|
|
@@ -5759,12 +6055,13 @@ window.__ModuleLoader__.load({
|
|
|
5759
6055
|
if (checks.length === 0) return void 0;
|
|
5760
6056
|
return checks.map((check) => `${check.name}|${check.link ?? ""}`).sort().join("\n");
|
|
5761
6057
|
}
|
|
5762
|
-
function planAutoFix(memory,
|
|
5763
|
-
const
|
|
6058
|
+
function planAutoFix(memory, threads, checks) {
|
|
6059
|
+
const unhandled = threads.filter((thread) => !thread.resolved).filter((thread) => thread.comments.some((comment) => !memory.handledCommentIds.has(comment.id)));
|
|
6060
|
+
const fresh = unhandled.flatMap((thread) => thread.comments);
|
|
5764
6061
|
const signature = checksSignature(checks);
|
|
5765
6062
|
const checksChanged = signature !== void 0 && signature !== memory.handledChecksSignature;
|
|
5766
6063
|
const sections = [];
|
|
5767
|
-
if (
|
|
6064
|
+
if (unhandled.length > 0) sections.push(composeCommentsPrompt(unhandled));
|
|
5768
6065
|
if (checksChanged) sections.push(composeChecksPrompt(checks));
|
|
5769
6066
|
if (sections.length === 0) return { memory };
|
|
5770
6067
|
const nextSignature = checksChanged ? signature : memory.handledChecksSignature;
|
|
@@ -5777,6 +6074,47 @@ window.__ModuleLoader__.load({
|
|
|
5777
6074
|
};
|
|
5778
6075
|
}
|
|
5779
6076
|
//#endregion
|
|
6077
|
+
//#region src/client/boot-check.ts
|
|
6078
|
+
/** Boot-time assertions against the running Host.
|
|
6079
|
+
*
|
|
6080
|
+
* The Desktop build ships no type declarations and several of its client
|
|
6081
|
+
* packages are unpublished, so `tsc` validates this plugin against whatever
|
|
6082
|
+
* @deepseek-ai/* versions happen to be installed — never against the Host it
|
|
6083
|
+
* will actually run inside. Every Desktop 2.0 breakage found so far was
|
|
6084
|
+
* invisible at compile time AND at runtime: a missing service leaves its
|
|
6085
|
+
* guarded registration silently unregistered, and a renamed custom property
|
|
6086
|
+
* just freezes a style on its fallback. These checks make that drift say so. */
|
|
6087
|
+
/** Host-owned custom properties the styles read, and where each is scoped.
|
|
6088
|
+
*
|
|
6089
|
+
* `var(--x, fallback)` cannot distinguish "the Host stopped publishing this"
|
|
6090
|
+
* from "the Host says this", so anything listed here needs an explicit probe.
|
|
6091
|
+
* The Host scopes these to a subtree rather than `:root` — custom properties
|
|
6092
|
+
* inherit, so only an element inside that subtree can see one, and probing
|
|
6093
|
+
* document.documentElement reports every one of them missing. Each entry
|
|
6094
|
+
* therefore names the mounted element that must be measured instead.
|
|
6095
|
+
*
|
|
6096
|
+
* Plugin-owned properties (--dsh-claude-*) are set by this package and are
|
|
6097
|
+
* deliberately absent from this list. */
|
|
6098
|
+
const CLAUDE_SCOPED_CSS_VARIABLES = ["--dsh-composer-card-max-width"];
|
|
6099
|
+
/** Marks the bar the scoped-property probe measures. */
|
|
6100
|
+
const CLAUDE_COMPOSER_BAR_ATTRIBUTE = "data-dsh-claude-composer-bar";
|
|
6101
|
+
/** One line per service the Host no longer provides; empty when all resolve. */
|
|
6102
|
+
function claudeBootCheckFindings(input) {
|
|
6103
|
+
const findings = [];
|
|
6104
|
+
for (const name of input.services) if (input.resolve(name) === void 0) findings.push(`service "${name}" is declared in inject but the Host does not provide it`);
|
|
6105
|
+
return findings;
|
|
6106
|
+
}
|
|
6107
|
+
/** One line per scoped custom property the measured element cannot see.
|
|
6108
|
+
*
|
|
6109
|
+
* @param read - computed value of one property ON THE MOUNTED BAR, not on the
|
|
6110
|
+
* document root: these properties are published to a subtree, so reading them
|
|
6111
|
+
* anywhere above it returns '' whether or not the Host still defines them. */
|
|
6112
|
+
function claudeScopedCssFindings(read, names = CLAUDE_SCOPED_CSS_VARIABLES) {
|
|
6113
|
+
const findings = [];
|
|
6114
|
+
for (const name of names) if (read(name).trim() === "") findings.push(`CSS custom property "${name}" is not visible to the composer bar; styles reading it are stuck on their fallback`);
|
|
6115
|
+
return findings;
|
|
6116
|
+
}
|
|
6117
|
+
//#endregion
|
|
5780
6118
|
//#region src/client/ClaudeRepositoryStatus.tsx
|
|
5781
6119
|
/** Icon-only status: the tone carries the state, the full label lives in the tooltip and accessible name. */
|
|
5782
6120
|
function StatusGlyph({ label, tone, children }) {
|
|
@@ -5900,15 +6238,6 @@ window.__ModuleLoader__.load({
|
|
|
5900
6238
|
function repositoryName$1(remote) {
|
|
5901
6239
|
return remote?.split("/").at(-1);
|
|
5902
6240
|
}
|
|
5903
|
-
function relativeAge(value) {
|
|
5904
|
-
if (value === void 0) return void 0;
|
|
5905
|
-
const elapsedHours = Math.max(0, Math.floor((Date.now() - Date.parse(value)) / 36e5));
|
|
5906
|
-
if (!Number.isFinite(elapsedHours)) return void 0;
|
|
5907
|
-
if (elapsedHours < 1) return "<1h";
|
|
5908
|
-
if (elapsedHours < 24) return `${elapsedHours}h`;
|
|
5909
|
-
const days = Math.floor(elapsedHours / 24);
|
|
5910
|
-
return days < 30 ? `${days}d` : `${Math.floor(days / 30)}mo`;
|
|
5911
|
-
}
|
|
5912
6241
|
function PullRequestHoverCard({ repository, t }) {
|
|
5913
6242
|
const pullRequest = repository.pullRequest;
|
|
5914
6243
|
if (pullRequest === void 0) return null;
|
|
@@ -6046,7 +6375,7 @@ window.__ModuleLoader__.load({
|
|
|
6046
6375
|
if (!enabled || !open || running || number === void 0 || submitPrompt === void 0) return;
|
|
6047
6376
|
let cancelled = false;
|
|
6048
6377
|
const tick = async () => {
|
|
6049
|
-
const [comments, failing] = await Promise.all([
|
|
6378
|
+
const [comments, failing] = await Promise.all([loadPullRequestThreads(sessionId, number).catch(() => []), checks === "failing" ? loadFailingChecks(sessionId, number).catch(() => []) : Promise.resolve([])]);
|
|
6050
6379
|
if (cancelled) return;
|
|
6051
6380
|
const plan = planAutoFix(autoFixMemory(sessionId), comments, failing);
|
|
6052
6381
|
if (plan.prompt !== void 0 && submitPrompt(plan.prompt, "idle")) rememberAutoFix(sessionId, plan.memory);
|
|
@@ -6216,7 +6545,7 @@ window.__ModuleLoader__.load({
|
|
|
6216
6545
|
}) : null]
|
|
6217
6546
|
});
|
|
6218
6547
|
}
|
|
6219
|
-
function UpdateBranchControl({ sessionId, repository, t, submitPrompt }) {
|
|
6548
|
+
function UpdateBranchControl({ sessionId, repository, t, report, submitPrompt }) {
|
|
6220
6549
|
const [dialog, setDialog] = useState();
|
|
6221
6550
|
const [method, setMethod] = useState("rebase");
|
|
6222
6551
|
const controller = useRef();
|
|
@@ -6224,11 +6553,6 @@ window.__ModuleLoader__.load({
|
|
|
6224
6553
|
const base = pullRequest?.baseBranch;
|
|
6225
6554
|
const behind = repository.baseBehind ?? 0;
|
|
6226
6555
|
useEffect(() => () => controller.current?.abort(), []);
|
|
6227
|
-
useEffect(() => {
|
|
6228
|
-
if (dialog?.pushed === void 0 || dialog.error !== void 0) return;
|
|
6229
|
-
const timer = setTimeout(() => setDialog(void 0), 1200);
|
|
6230
|
-
return () => clearTimeout(timer);
|
|
6231
|
-
}, [dialog?.error, dialog?.pushed]);
|
|
6232
6556
|
if (pullRequest === void 0 || pullRequest.state !== "open" || base === void 0 || repository.detached === true || repository.dirty === true || behind <= 0) return null;
|
|
6233
6557
|
const openDialog = () => {
|
|
6234
6558
|
controller.current?.abort();
|
|
@@ -6273,11 +6597,16 @@ window.__ModuleLoader__.load({
|
|
|
6273
6597
|
baseBranch: base,
|
|
6274
6598
|
mergeMethod: method
|
|
6275
6599
|
}).then((result) => {
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6600
|
+
if (result.conflicts !== void 0 && result.conflicts.length > 0) {
|
|
6601
|
+
setDialog({
|
|
6602
|
+
...pending,
|
|
6603
|
+
submitting: false,
|
|
6604
|
+
conflicts: result.conflicts
|
|
6605
|
+
});
|
|
6606
|
+
return;
|
|
6607
|
+
}
|
|
6608
|
+
report(t("diffUpdateBranchCompleted", { commit: result.commit.slice(0, 8) }));
|
|
6609
|
+
setDialog(void 0);
|
|
6281
6610
|
}, (reason) => {
|
|
6282
6611
|
setDialog({
|
|
6283
6612
|
...pending,
|
|
@@ -6286,7 +6615,7 @@ window.__ModuleLoader__.load({
|
|
|
6286
6615
|
});
|
|
6287
6616
|
});
|
|
6288
6617
|
};
|
|
6289
|
-
const settled = dialog?.
|
|
6618
|
+
const settled = dialog?.conflicts !== void 0;
|
|
6290
6619
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6291
6620
|
/* @__PURE__ */ jsxs("button", {
|
|
6292
6621
|
type: "button",
|
|
@@ -6365,10 +6694,6 @@ window.__ModuleLoader__.load({
|
|
|
6365
6694
|
onChange: () => setMethod(option)
|
|
6366
6695
|
}), t(`diffUpdateBranch_${option}`, { base })]
|
|
6367
6696
|
}, option)),
|
|
6368
|
-
dialog.pushed === void 0 ? null : /* @__PURE__ */ jsx("p", {
|
|
6369
|
-
style: diffModalSuccess,
|
|
6370
|
-
children: t("diffUpdateBranchCompleted", { commit: dialog.pushed.slice(0, 8) })
|
|
6371
|
-
}),
|
|
6372
6697
|
dialog.conflicts === void 0 ? null : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6373
6698
|
/* @__PURE__ */ jsx("p", {
|
|
6374
6699
|
style: diffModalStatus,
|
|
@@ -6401,15 +6726,10 @@ window.__ModuleLoader__.load({
|
|
|
6401
6726
|
/** After a merge: remove the worktree (or switch a plain checkout back to
|
|
6402
6727
|
* base), delete the merged branch, and drop the DSH workspace along with the
|
|
6403
6728
|
* sessions it held. */
|
|
6404
|
-
function CleanupControl({ repository, t, deleteWorkspace }) {
|
|
6729
|
+
function CleanupControl({ repository, t, report, deleteWorkspace }) {
|
|
6405
6730
|
const [dialog, setDialog] = useState();
|
|
6406
6731
|
const pullRequest = repository.pullRequest;
|
|
6407
6732
|
const base = pullRequest?.baseBranch;
|
|
6408
|
-
useEffect(() => {
|
|
6409
|
-
if (dialog?.done === void 0) return;
|
|
6410
|
-
const timer = setTimeout(() => setDialog(void 0), 1500);
|
|
6411
|
-
return () => clearTimeout(timer);
|
|
6412
|
-
}, [dialog?.done]);
|
|
6413
6733
|
if (pullRequest?.state !== "merged" || base === void 0 || repository.root === void 0 || repository.detached === true) return null;
|
|
6414
6734
|
const root = repository.root;
|
|
6415
6735
|
const closeDialog = () => {
|
|
@@ -6418,11 +6738,9 @@ window.__ModuleLoader__.load({
|
|
|
6418
6738
|
const confirm = () => {
|
|
6419
6739
|
setDialog({ submitting: true });
|
|
6420
6740
|
cleanupMergedRepository(root, base).then(async (result) => {
|
|
6741
|
+
report(t("cleanupCompleted", { branch: result.branch }));
|
|
6742
|
+
setDialog(void 0);
|
|
6421
6743
|
if (result.mode === "worktree" && deleteWorkspace !== void 0) await deleteWorkspace();
|
|
6422
|
-
setDialog({
|
|
6423
|
-
submitting: false,
|
|
6424
|
-
done: result.branch
|
|
6425
|
-
});
|
|
6426
6744
|
}, (reason) => {
|
|
6427
6745
|
setDialog({
|
|
6428
6746
|
submitting: false,
|
|
@@ -6462,8 +6780,8 @@ window.__ModuleLoader__.load({
|
|
|
6462
6780
|
},
|
|
6463
6781
|
disabled: dialog?.submitting === true,
|
|
6464
6782
|
onClick: closeDialog,
|
|
6465
|
-
children:
|
|
6466
|
-
}),
|
|
6783
|
+
children: t("diffCancel")
|
|
6784
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
6467
6785
|
type: "button",
|
|
6468
6786
|
style: {
|
|
6469
6787
|
...primaryButton,
|
|
@@ -6472,35 +6790,28 @@ window.__ModuleLoader__.load({
|
|
|
6472
6790
|
disabled: dialog?.submitting === true,
|
|
6473
6791
|
onClick: confirm,
|
|
6474
6792
|
children: dialog?.submitting === true ? t("diffSubmitting") : t("diffConfirm")
|
|
6475
|
-
})
|
|
6793
|
+
})]
|
|
6476
6794
|
}),
|
|
6477
6795
|
children: dialog === void 0 ? null : /* @__PURE__ */ jsxs("div", {
|
|
6478
6796
|
style: diffModalBody,
|
|
6479
|
-
children: [
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
}),
|
|
6498
|
-
dialog.error === void 0 ? null : /* @__PURE__ */ jsx("p", {
|
|
6499
|
-
role: "alert",
|
|
6500
|
-
style: diffModalError,
|
|
6501
|
-
children: dialog.error
|
|
6502
|
-
})
|
|
6503
|
-
]
|
|
6797
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
6798
|
+
style: diffModalMeta,
|
|
6799
|
+
children: [/* @__PURE__ */ jsxs("strong", {
|
|
6800
|
+
style: diffModalMetaText,
|
|
6801
|
+
children: [
|
|
6802
|
+
repository.branch ?? t("repositoryUnknownBranch"),
|
|
6803
|
+
" → ",
|
|
6804
|
+
base
|
|
6805
|
+
]
|
|
6806
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
6807
|
+
style: diffModalFileState,
|
|
6808
|
+
children: repository.worktree === true ? t("repositoryWorktree") : t("repositoryLocal")
|
|
6809
|
+
})]
|
|
6810
|
+
}), dialog.error === void 0 ? null : /* @__PURE__ */ jsx("p", {
|
|
6811
|
+
role: "alert",
|
|
6812
|
+
style: diffModalError,
|
|
6813
|
+
children: dialog.error
|
|
6814
|
+
})]
|
|
6504
6815
|
})
|
|
6505
6816
|
})
|
|
6506
6817
|
] });
|
|
@@ -6510,17 +6821,12 @@ window.__ModuleLoader__.load({
|
|
|
6510
6821
|
"squash",
|
|
6511
6822
|
"rebase"
|
|
6512
6823
|
];
|
|
6513
|
-
function MergePullRequestControl({ sessionId, repository, t }) {
|
|
6824
|
+
function MergePullRequestControl({ sessionId, repository, t, report }) {
|
|
6514
6825
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
6515
6826
|
const [dialog, setDialog] = useState();
|
|
6516
6827
|
const controller = useRef();
|
|
6517
6828
|
const pullRequest = repository.pullRequest;
|
|
6518
6829
|
useEffect(() => () => controller.current?.abort(), []);
|
|
6519
|
-
useEffect(() => {
|
|
6520
|
-
if (dialog?.merged !== true || dialog.error !== void 0) return;
|
|
6521
|
-
const timer = setTimeout(() => setDialog(void 0), 1200);
|
|
6522
|
-
return () => clearTimeout(timer);
|
|
6523
|
-
}, [dialog?.error, dialog?.merged]);
|
|
6524
6830
|
if (pullRequest === void 0 || pullRequest.state !== "open" || pullRequest.draft || repository.detached === true) return null;
|
|
6525
6831
|
const openMerge = (method) => {
|
|
6526
6832
|
controller.current?.abort();
|
|
@@ -6568,11 +6874,8 @@ window.__ModuleLoader__.load({
|
|
|
6568
6874
|
includeUnstaged: false,
|
|
6569
6875
|
mergeMethod: dialog.method
|
|
6570
6876
|
}).then(() => {
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
submitting: false,
|
|
6574
|
-
merged: true
|
|
6575
|
-
});
|
|
6877
|
+
report(t("diffMergeCompleted", { number: pullRequest.number }));
|
|
6878
|
+
setDialog(void 0);
|
|
6576
6879
|
}, (error) => {
|
|
6577
6880
|
setDialog({
|
|
6578
6881
|
...pending,
|
|
@@ -6581,15 +6884,13 @@ window.__ModuleLoader__.load({
|
|
|
6581
6884
|
});
|
|
6582
6885
|
});
|
|
6583
6886
|
};
|
|
6584
|
-
const items = MERGE_METHODS.map((method) => ({
|
|
6585
|
-
id: method,
|
|
6586
|
-
label: t(`diffMerge_${method}`)
|
|
6587
|
-
}));
|
|
6588
|
-
const merged = dialog?.merged === true;
|
|
6589
6887
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6590
6888
|
/* @__PURE__ */ jsx(Menu, {
|
|
6591
6889
|
open: menuOpen,
|
|
6592
|
-
items
|
|
6890
|
+
items: MERGE_METHODS.map((method) => ({
|
|
6891
|
+
id: method,
|
|
6892
|
+
label: t(`diffMerge_${method}`)
|
|
6893
|
+
})),
|
|
6593
6894
|
onSelect: (id) => openMerge(id),
|
|
6594
6895
|
onClose: () => setMenuOpen(false),
|
|
6595
6896
|
align: "end",
|
|
@@ -6626,8 +6927,8 @@ window.__ModuleLoader__.load({
|
|
|
6626
6927
|
},
|
|
6627
6928
|
disabled: dialog?.submitting === true,
|
|
6628
6929
|
onClick: closeDialog,
|
|
6629
|
-
children:
|
|
6630
|
-
}),
|
|
6930
|
+
children: t("diffCancel")
|
|
6931
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
6631
6932
|
type: "button",
|
|
6632
6933
|
style: {
|
|
6633
6934
|
...primaryButton,
|
|
@@ -6636,7 +6937,7 @@ window.__ModuleLoader__.load({
|
|
|
6636
6937
|
disabled: dialog?.loading === true || dialog?.submitting === true || dialog?.fingerprint === void 0,
|
|
6637
6938
|
onClick: confirmMerge,
|
|
6638
6939
|
children: dialog?.submitting === true ? t("diffSubmitting") : t("diffConfirm")
|
|
6639
|
-
})
|
|
6940
|
+
})]
|
|
6640
6941
|
}),
|
|
6641
6942
|
children: dialog === void 0 ? null : /* @__PURE__ */ jsxs("div", {
|
|
6642
6943
|
style: diffModalBody,
|
|
@@ -6660,10 +6961,6 @@ window.__ModuleLoader__.load({
|
|
|
6660
6961
|
style: diffModalStatus,
|
|
6661
6962
|
children: pullRequest.title
|
|
6662
6963
|
}),
|
|
6663
|
-
merged ? /* @__PURE__ */ jsx("p", {
|
|
6664
|
-
style: diffModalSuccess,
|
|
6665
|
-
children: t("diffMergeCompleted", { number: pullRequest.number })
|
|
6666
|
-
}) : null,
|
|
6667
6964
|
dialog.error === void 0 ? null : /* @__PURE__ */ jsx("p", {
|
|
6668
6965
|
role: "alert",
|
|
6669
6966
|
style: diffModalError,
|
|
@@ -6679,6 +6976,7 @@ window.__ModuleLoader__.load({
|
|
|
6679
6976
|
const running = useSessions((value) => value.byId[sessionId]?.running === true);
|
|
6680
6977
|
const projection = useClaudeProjection((value) => value);
|
|
6681
6978
|
const repository = projection.repository;
|
|
6979
|
+
const { toast, report } = useActionToast();
|
|
6682
6980
|
if (blank || !projection.owned || repository === void 0) return null;
|
|
6683
6981
|
const branch = repository.detached === true ? t("repositoryDetached") : repository.branch ?? t("repositoryUnknownBranch");
|
|
6684
6982
|
const pullRequest = repository.pullRequest;
|
|
@@ -6689,6 +6987,7 @@ window.__ModuleLoader__.load({
|
|
|
6689
6987
|
const hasDiff = repository.diff !== void 0 && (repository.diff.additions > 0 || repository.diff.deletions > 0);
|
|
6690
6988
|
if (repository.status !== "ready") return /* @__PURE__ */ jsx("div", {
|
|
6691
6989
|
style: repositoryBarFrame,
|
|
6990
|
+
[CLAUDE_COMPOSER_BAR_ATTRIBUTE]: "",
|
|
6692
6991
|
children: /* @__PURE__ */ jsxs("div", {
|
|
6693
6992
|
style: repositoryBar,
|
|
6694
6993
|
children: [/* @__PURE__ */ jsx("span", {
|
|
@@ -6700,9 +6999,10 @@ window.__ModuleLoader__.load({
|
|
|
6700
6999
|
})]
|
|
6701
7000
|
})
|
|
6702
7001
|
});
|
|
6703
|
-
return /* @__PURE__ */
|
|
7002
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
6704
7003
|
style: repositoryBarFrame,
|
|
6705
|
-
|
|
7004
|
+
[CLAUDE_COMPOSER_BAR_ATTRIBUTE]: "",
|
|
7005
|
+
children: [toast, /* @__PURE__ */ jsxs("div", {
|
|
6706
7006
|
style: {
|
|
6707
7007
|
...repositoryBar,
|
|
6708
7008
|
...merged ? repositoryBarMerged : {}
|
|
@@ -6778,6 +7078,7 @@ window.__ModuleLoader__.load({
|
|
|
6778
7078
|
}), /* @__PURE__ */ jsx(CleanupControl, {
|
|
6779
7079
|
repository,
|
|
6780
7080
|
t,
|
|
7081
|
+
report,
|
|
6781
7082
|
...deleteWorkspace === void 0 ? {} : { deleteWorkspace }
|
|
6782
7083
|
})] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
6783
7084
|
pullRequest.checks === "failing" ? /* @__PURE__ */ jsx(FailingChecksControl, {
|
|
@@ -6806,17 +7107,19 @@ window.__ModuleLoader__.load({
|
|
|
6806
7107
|
sessionId,
|
|
6807
7108
|
repository,
|
|
6808
7109
|
t,
|
|
7110
|
+
report,
|
|
6809
7111
|
...submitPrompt === void 0 ? {} : { submitPrompt }
|
|
6810
7112
|
}),
|
|
6811
7113
|
/* @__PURE__ */ jsx(MergePullRequestControl, {
|
|
6812
7114
|
sessionId,
|
|
6813
7115
|
repository,
|
|
6814
|
-
t
|
|
7116
|
+
t,
|
|
7117
|
+
report
|
|
6815
7118
|
})
|
|
6816
7119
|
] })]
|
|
6817
7120
|
})
|
|
6818
7121
|
]
|
|
6819
|
-
})
|
|
7122
|
+
})]
|
|
6820
7123
|
});
|
|
6821
7124
|
}
|
|
6822
7125
|
//#endregion
|
|
@@ -11134,24 +11437,424 @@ window.__ModuleLoader__.load({
|
|
|
11134
11437
|
ADD_ATTR: ["target", "rel"]
|
|
11135
11438
|
});
|
|
11136
11439
|
}
|
|
11137
|
-
/** One review comment body, ready for `dangerouslySetInnerHTML`. */
|
|
11138
|
-
function renderCommentBody(body, purify$2 = purify) {
|
|
11139
|
-
return sanitizeCommentHtml(commentBodyHtml(body), purify$2);
|
|
11440
|
+
/** One review comment body, ready for `dangerouslySetInnerHTML`. */
|
|
11441
|
+
function renderCommentBody(body, purify$2 = purify) {
|
|
11442
|
+
return sanitizeCommentHtml(commentBodyHtml(body), purify$2);
|
|
11443
|
+
}
|
|
11444
|
+
/** Open sanitized links in the browser instead of inside the app shell, and
|
|
11445
|
+
* keep comment checkboxes inert. Installed once, on import, so no render
|
|
11446
|
+
* path can reach the sanitizer before its hooks. */
|
|
11447
|
+
function installCommentSanitizerHooks(purify$3 = purify) {
|
|
11448
|
+
if (typeof purify$3.addHook !== "function" || purify$3.isSupported !== true) return;
|
|
11449
|
+
purify$3.addHook("afterSanitizeAttributes", (node) => {
|
|
11450
|
+
if (node.nodeName === "A") {
|
|
11451
|
+
node.setAttribute("target", "_blank");
|
|
11452
|
+
node.setAttribute("rel", "noopener noreferrer");
|
|
11453
|
+
}
|
|
11454
|
+
if (node.nodeName === "INPUT") node.setAttribute("disabled", "");
|
|
11455
|
+
});
|
|
11456
|
+
}
|
|
11457
|
+
installCommentSanitizerHooks();
|
|
11458
|
+
//#endregion
|
|
11459
|
+
//#region src/client/mention.ts
|
|
11460
|
+
/** `@` completion for the review reply composer.
|
|
11461
|
+
*
|
|
11462
|
+
* GitHub resolves `@login` server-side, so completion is convenience only:
|
|
11463
|
+
* every function here works on the draft text, never on the network. */
|
|
11464
|
+
/** GitHub logins are alphanumeric with dashes; app accounts add a `[bot]`
|
|
11465
|
+
* suffix, which the user reaches by continuing to type rather than by us
|
|
11466
|
+
* matching it here. */
|
|
11467
|
+
const HANDLE = /(?:^|[^\w@/-])@([\w-]*)$/u;
|
|
11468
|
+
const MAX_HANDLE_CHARS = 39;
|
|
11469
|
+
/** The handle the caret is currently inside, when it is inside one. */
|
|
11470
|
+
function mentionQueryAt(text, caret) {
|
|
11471
|
+
const before = text.slice(0, caret);
|
|
11472
|
+
const match = HANDLE.exec(before);
|
|
11473
|
+
const query = match?.[1];
|
|
11474
|
+
if (match === void 0 || match === null || query === void 0 || query.length > MAX_HANDLE_CHARS) return void 0;
|
|
11475
|
+
return {
|
|
11476
|
+
query,
|
|
11477
|
+
start: caret - query.length - 1
|
|
11478
|
+
};
|
|
11479
|
+
}
|
|
11480
|
+
/** Swap the typed handle for the chosen login, leaving a separating space. */
|
|
11481
|
+
function applyMention(text, caret, mention, login) {
|
|
11482
|
+
const completed = `@${login} `;
|
|
11483
|
+
return {
|
|
11484
|
+
text: `${text.slice(0, mention.start)}${completed}${text.slice(caret)}`,
|
|
11485
|
+
caret: mention.start + completed.length
|
|
11486
|
+
};
|
|
11487
|
+
}
|
|
11488
|
+
//#endregion
|
|
11489
|
+
//#region src/client/menu-navigation.ts
|
|
11490
|
+
/** Wrapping keyboard navigation shared by the plugin's popup lists. */
|
|
11491
|
+
function menuNavigationIndex(current, count, key) {
|
|
11492
|
+
if (count <= 0) return 0;
|
|
11493
|
+
if (key === "Home") return 0;
|
|
11494
|
+
if (key === "End") return count - 1;
|
|
11495
|
+
return (current + (key === "ArrowDown" ? 1 : -1) + count) % count;
|
|
11496
|
+
}
|
|
11497
|
+
//#endregion
|
|
11498
|
+
//#region src/client/MentionTextarea.tsx
|
|
11499
|
+
/** How long the draft must sit still before the repository is asked who `@al`
|
|
11500
|
+
* might be; one request per keystroke would rate-limit the token. */
|
|
11501
|
+
const SUGGEST_DEBOUNCE_MS = 200;
|
|
11502
|
+
/** A comment composer that completes `@handles` from the repository's
|
|
11503
|
+
* mentionable users. GitHub notifies on the text alone, so the popup is a
|
|
11504
|
+
* convenience: typing a login by hand works exactly as well. */
|
|
11505
|
+
function MentionTextarea({ value, placeholder, suggestLabel, maxLength = 2e3, autoFocus = false, disabled = false, suggest, onChange, onSubmit }) {
|
|
11506
|
+
const areaRef = useRef(null);
|
|
11507
|
+
const [mention, setMention] = useState();
|
|
11508
|
+
const [users, setUsers] = useState([]);
|
|
11509
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
11510
|
+
const [caretTarget, setCaretTarget] = useState();
|
|
11511
|
+
const open = mention !== void 0 && users.length > 0;
|
|
11512
|
+
useEffect(() => {
|
|
11513
|
+
if (mention === void 0) {
|
|
11514
|
+
setUsers([]);
|
|
11515
|
+
return;
|
|
11516
|
+
}
|
|
11517
|
+
let cancelled = false;
|
|
11518
|
+
const timer = setTimeout(() => {
|
|
11519
|
+
suggest(mention.query).then((found) => {
|
|
11520
|
+
if (cancelled) return;
|
|
11521
|
+
setUsers(found);
|
|
11522
|
+
setActiveIndex(0);
|
|
11523
|
+
}, () => {
|
|
11524
|
+
if (!cancelled) setUsers([]);
|
|
11525
|
+
});
|
|
11526
|
+
}, SUGGEST_DEBOUNCE_MS);
|
|
11527
|
+
return () => {
|
|
11528
|
+
cancelled = true;
|
|
11529
|
+
clearTimeout(timer);
|
|
11530
|
+
};
|
|
11531
|
+
}, [mention, suggest]);
|
|
11532
|
+
useLayoutEffect(() => {
|
|
11533
|
+
if (caretTarget === void 0 || areaRef.current === null) return;
|
|
11534
|
+
areaRef.current.setSelectionRange(caretTarget, caretTarget);
|
|
11535
|
+
setCaretTarget(void 0);
|
|
11536
|
+
}, [caretTarget, value]);
|
|
11537
|
+
const track = (area) => {
|
|
11538
|
+
setMention(mentionQueryAt(area.value, area.selectionStart ?? area.value.length));
|
|
11539
|
+
};
|
|
11540
|
+
const complete = (login) => {
|
|
11541
|
+
const area = areaRef.current;
|
|
11542
|
+
if (area === null || mention === void 0) return;
|
|
11543
|
+
const applied = applyMention(area.value, area.selectionStart ?? area.value.length, mention, login);
|
|
11544
|
+
setMention(void 0);
|
|
11545
|
+
setUsers([]);
|
|
11546
|
+
setCaretTarget(applied.caret);
|
|
11547
|
+
onChange(applied.text);
|
|
11548
|
+
};
|
|
11549
|
+
const handleKeyDown = (event) => {
|
|
11550
|
+
if (open) {
|
|
11551
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Home" || event.key === "End") {
|
|
11552
|
+
event.preventDefault();
|
|
11553
|
+
setActiveIndex((current) => menuNavigationIndex(current, users.length, event.key));
|
|
11554
|
+
return;
|
|
11555
|
+
}
|
|
11556
|
+
if (event.key === "Enter" || event.key === "Tab") {
|
|
11557
|
+
const login = users[activeIndex]?.login;
|
|
11558
|
+
if (login !== void 0) {
|
|
11559
|
+
event.preventDefault();
|
|
11560
|
+
complete(login);
|
|
11561
|
+
return;
|
|
11562
|
+
}
|
|
11563
|
+
}
|
|
11564
|
+
if (event.key === "Escape") {
|
|
11565
|
+
event.preventDefault();
|
|
11566
|
+
setMention(void 0);
|
|
11567
|
+
setUsers([]);
|
|
11568
|
+
return;
|
|
11569
|
+
}
|
|
11570
|
+
}
|
|
11571
|
+
if (event.key === "Enter" && (event.ctrlKey || event.metaKey) && onSubmit !== void 0) {
|
|
11572
|
+
event.preventDefault();
|
|
11573
|
+
onSubmit();
|
|
11574
|
+
}
|
|
11575
|
+
};
|
|
11576
|
+
return /* @__PURE__ */ jsxs("span", {
|
|
11577
|
+
style: mentionField,
|
|
11578
|
+
children: [/* @__PURE__ */ jsx("textarea", {
|
|
11579
|
+
ref: areaRef,
|
|
11580
|
+
className: diffCommentTextareaClass,
|
|
11581
|
+
style: diffCommentTextarea,
|
|
11582
|
+
value,
|
|
11583
|
+
maxLength,
|
|
11584
|
+
placeholder,
|
|
11585
|
+
disabled,
|
|
11586
|
+
autoFocus,
|
|
11587
|
+
"aria-autocomplete": "list",
|
|
11588
|
+
onChange: (event) => {
|
|
11589
|
+
onChange(event.currentTarget.value);
|
|
11590
|
+
track(event.currentTarget);
|
|
11591
|
+
},
|
|
11592
|
+
onKeyUp: (event) => {
|
|
11593
|
+
track(event.currentTarget);
|
|
11594
|
+
},
|
|
11595
|
+
onClick: (event) => {
|
|
11596
|
+
track(event.currentTarget);
|
|
11597
|
+
},
|
|
11598
|
+
onBlur: () => {
|
|
11599
|
+
setMention(void 0);
|
|
11600
|
+
},
|
|
11601
|
+
onKeyDown: handleKeyDown
|
|
11602
|
+
}), !open ? null : /* @__PURE__ */ jsx("span", {
|
|
11603
|
+
role: "listbox",
|
|
11604
|
+
"aria-label": suggestLabel,
|
|
11605
|
+
style: mentionList,
|
|
11606
|
+
children: users.map((user, index) => /* @__PURE__ */ jsxs("button", {
|
|
11607
|
+
type: "button",
|
|
11608
|
+
role: "option",
|
|
11609
|
+
"aria-selected": index === activeIndex,
|
|
11610
|
+
style: {
|
|
11611
|
+
...mentionItem,
|
|
11612
|
+
...index === activeIndex ? mentionItemActive : {}
|
|
11613
|
+
},
|
|
11614
|
+
onMouseEnter: () => {
|
|
11615
|
+
setActiveIndex(index);
|
|
11616
|
+
},
|
|
11617
|
+
onMouseDown: (event) => {
|
|
11618
|
+
event.preventDefault();
|
|
11619
|
+
},
|
|
11620
|
+
onClick: () => {
|
|
11621
|
+
complete(user.login);
|
|
11622
|
+
},
|
|
11623
|
+
children: [user.avatarUrl === void 0 ? null : /* @__PURE__ */ jsx("img", {
|
|
11624
|
+
src: user.avatarUrl,
|
|
11625
|
+
alt: "",
|
|
11626
|
+
width: 16,
|
|
11627
|
+
height: 16,
|
|
11628
|
+
loading: "lazy",
|
|
11629
|
+
referrerPolicy: "no-referrer",
|
|
11630
|
+
style: mentionAvatar
|
|
11631
|
+
}), user.login]
|
|
11632
|
+
}, user.login))
|
|
11633
|
+
})]
|
|
11634
|
+
});
|
|
11635
|
+
}
|
|
11636
|
+
//#endregion
|
|
11637
|
+
//#region src/client/ReviewThreadCard.tsx
|
|
11638
|
+
const BOT_SUFFIX = "[bot]";
|
|
11639
|
+
/** GitHub prints an app account as its name plus a Bot pill rather than as the
|
|
11640
|
+
* raw `name[bot]` login. GraphQL already drops that suffix, so the flag from
|
|
11641
|
+
* the API decides and the suffix is only stripped for display. */
|
|
11642
|
+
function identity(author) {
|
|
11643
|
+
return author.endsWith(BOT_SUFFIX) ? author.slice(0, -5) : author;
|
|
11644
|
+
}
|
|
11645
|
+
function CommentBody({ comment, t, now, first }) {
|
|
11646
|
+
const name = identity(comment.author);
|
|
11647
|
+
const age = relativeAge(comment.createdAt, now);
|
|
11648
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
11649
|
+
style: {
|
|
11650
|
+
...diffGhComment,
|
|
11651
|
+
...first ? {} : diffGhCommentNext
|
|
11652
|
+
},
|
|
11653
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
11654
|
+
style: diffCommentCardMeta,
|
|
11655
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
11656
|
+
style: diffGhCommentIdentity,
|
|
11657
|
+
children: [
|
|
11658
|
+
comment.avatarUrl === void 0 ? null : /* @__PURE__ */ jsx("img", {
|
|
11659
|
+
src: comment.avatarUrl,
|
|
11660
|
+
alt: "",
|
|
11661
|
+
width: 16,
|
|
11662
|
+
height: 16,
|
|
11663
|
+
loading: "lazy",
|
|
11664
|
+
referrerPolicy: "no-referrer",
|
|
11665
|
+
style: diffGhCommentAvatar,
|
|
11666
|
+
onError: (event) => {
|
|
11667
|
+
event.currentTarget.style.display = "none";
|
|
11668
|
+
}
|
|
11669
|
+
}),
|
|
11670
|
+
/* @__PURE__ */ jsxs("span", {
|
|
11671
|
+
style: diffGhCommentAuthor,
|
|
11672
|
+
children: ["@", name]
|
|
11673
|
+
}),
|
|
11674
|
+
comment.bot !== true ? null : /* @__PURE__ */ jsx("span", {
|
|
11675
|
+
style: diffThreadBadge,
|
|
11676
|
+
children: t("reviewThreadBot")
|
|
11677
|
+
}),
|
|
11678
|
+
age === void 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
11679
|
+
style: diffGhCommentAge,
|
|
11680
|
+
children: t("reviewThreadAgo", { age })
|
|
11681
|
+
})
|
|
11682
|
+
]
|
|
11683
|
+
}), /* @__PURE__ */ jsx(Tooltip, {
|
|
11684
|
+
label: t("reviewThreadOpenOnGitHub"),
|
|
11685
|
+
side: "bottom",
|
|
11686
|
+
delayMs: 250,
|
|
11687
|
+
children: /* @__PURE__ */ jsx("a", {
|
|
11688
|
+
href: comment.url,
|
|
11689
|
+
target: "_blank",
|
|
11690
|
+
rel: "noopener noreferrer",
|
|
11691
|
+
style: diffGhCommentLink,
|
|
11692
|
+
"aria-label": t("reviewThreadOpenOnGitHub"),
|
|
11693
|
+
children: /* @__PURE__ */ jsx(IconRightUpOutline14, {})
|
|
11694
|
+
})
|
|
11695
|
+
})]
|
|
11696
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
11697
|
+
style: diffCommentCardText,
|
|
11698
|
+
className: "dshClaudeDiffCommentBody",
|
|
11699
|
+
dangerouslySetInnerHTML: { __html: renderCommentBody(comment.body) }
|
|
11700
|
+
})]
|
|
11701
|
+
});
|
|
11140
11702
|
}
|
|
11141
|
-
/**
|
|
11142
|
-
*
|
|
11143
|
-
*
|
|
11144
|
-
|
|
11145
|
-
|
|
11146
|
-
|
|
11147
|
-
|
|
11148
|
-
|
|
11149
|
-
|
|
11703
|
+
/** One GitHub review conversation, anchored on its diff line: every comment in
|
|
11704
|
+
* the thread, plus the two things a reviewer expects to do with it — answer it
|
|
11705
|
+
* and close it. A resolved thread collapses, because the diff is about what
|
|
11706
|
+
* still needs attention. */
|
|
11707
|
+
function ReviewThreadCard({ thread, t, now, anchorKey, active = false, suggest, onReply, onResolvedChange }) {
|
|
11708
|
+
const [expanded, setExpanded] = useState(false);
|
|
11709
|
+
const [replying, setReplying] = useState(false);
|
|
11710
|
+
const [draft, setDraft] = useState("");
|
|
11711
|
+
const [busy, setBusy] = useState(false);
|
|
11712
|
+
const [error, setError] = useState();
|
|
11713
|
+
const first = thread.comments[0];
|
|
11714
|
+
if (first === void 0) return null;
|
|
11715
|
+
const collapsed = thread.resolved && !expanded;
|
|
11716
|
+
const send = () => {
|
|
11717
|
+
const body = draft.trim();
|
|
11718
|
+
if (body.length === 0 || busy) return;
|
|
11719
|
+
setBusy(true);
|
|
11720
|
+
setError(void 0);
|
|
11721
|
+
onReply(body).then(() => {
|
|
11722
|
+
setDraft("");
|
|
11723
|
+
setReplying(false);
|
|
11724
|
+
}, (reason) => {
|
|
11725
|
+
setError(reason instanceof Error ? reason.message : t("reviewThreadReplyFailed"));
|
|
11726
|
+
}).finally(() => {
|
|
11727
|
+
setBusy(false);
|
|
11728
|
+
});
|
|
11729
|
+
};
|
|
11730
|
+
const toggleResolved = () => {
|
|
11731
|
+
if (busy) return;
|
|
11732
|
+
setBusy(true);
|
|
11733
|
+
setError(void 0);
|
|
11734
|
+
onResolvedChange(!thread.resolved).catch((reason) => {
|
|
11735
|
+
setError(reason instanceof Error ? reason.message : t("reviewThreadResolveFailed"));
|
|
11736
|
+
}).finally(() => {
|
|
11737
|
+
setBusy(false);
|
|
11738
|
+
});
|
|
11739
|
+
};
|
|
11740
|
+
const frame = {
|
|
11741
|
+
...anchorKey === void 0 ? {} : { "data-review-target": anchorKey },
|
|
11742
|
+
...active ? { "data-review-active": "true" } : {},
|
|
11743
|
+
style: {
|
|
11744
|
+
...diffCommentBlock,
|
|
11745
|
+
...active ? diffCommentBlockActive : {}
|
|
11150
11746
|
}
|
|
11151
|
-
|
|
11747
|
+
};
|
|
11748
|
+
if (collapsed) return /* @__PURE__ */ jsx("div", {
|
|
11749
|
+
...frame,
|
|
11750
|
+
children: /* @__PURE__ */ jsxs("button", {
|
|
11751
|
+
type: "button",
|
|
11752
|
+
"aria-expanded": false,
|
|
11753
|
+
style: diffThreadSummary,
|
|
11754
|
+
onClick: () => {
|
|
11755
|
+
setExpanded(true);
|
|
11756
|
+
},
|
|
11757
|
+
children: [
|
|
11758
|
+
/* @__PURE__ */ jsx("span", {
|
|
11759
|
+
style: diffThreadBadge,
|
|
11760
|
+
children: t("reviewThreadResolved")
|
|
11761
|
+
}),
|
|
11762
|
+
/* @__PURE__ */ jsxs("span", {
|
|
11763
|
+
style: diffGhCommentAuthor,
|
|
11764
|
+
children: ["@", identity(first.author)]
|
|
11765
|
+
}),
|
|
11766
|
+
/* @__PURE__ */ jsx("span", {
|
|
11767
|
+
style: diffThreadExcerpt,
|
|
11768
|
+
children: first.body.split("\n")[0]
|
|
11769
|
+
})
|
|
11770
|
+
]
|
|
11771
|
+
})
|
|
11772
|
+
});
|
|
11773
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
11774
|
+
...frame,
|
|
11775
|
+
children: [
|
|
11776
|
+
!thread.resolved && !thread.outdated ? null : /* @__PURE__ */ jsxs("div", {
|
|
11777
|
+
style: diffThreadBadges,
|
|
11778
|
+
children: [thread.resolved ? /* @__PURE__ */ jsx("span", {
|
|
11779
|
+
style: diffThreadBadge,
|
|
11780
|
+
children: t("reviewThreadResolved")
|
|
11781
|
+
}) : null, thread.outdated ? /* @__PURE__ */ jsx("span", {
|
|
11782
|
+
style: diffThreadBadge,
|
|
11783
|
+
children: t("reviewThreadOutdated")
|
|
11784
|
+
}) : null]
|
|
11785
|
+
}),
|
|
11786
|
+
thread.comments.map((comment, index) => /* @__PURE__ */ jsx(CommentBody, {
|
|
11787
|
+
comment,
|
|
11788
|
+
t,
|
|
11789
|
+
now,
|
|
11790
|
+
first: index === 0
|
|
11791
|
+
}, comment.id)),
|
|
11792
|
+
error === void 0 ? null : /* @__PURE__ */ jsx("p", {
|
|
11793
|
+
style: diffCommentError,
|
|
11794
|
+
children: error
|
|
11795
|
+
}),
|
|
11796
|
+
replying ? /* @__PURE__ */ jsxs("div", {
|
|
11797
|
+
"data-review-reply": "",
|
|
11798
|
+
style: diffThreadComposer,
|
|
11799
|
+
children: [
|
|
11800
|
+
/* @__PURE__ */ jsx("span", {
|
|
11801
|
+
style: diffThreadComposerCaption,
|
|
11802
|
+
children: t("reviewThreadReplyTo", { author: identity(thread.comments[thread.comments.length - 1]?.author ?? first.author) })
|
|
11803
|
+
}),
|
|
11804
|
+
/* @__PURE__ */ jsx(MentionTextarea, {
|
|
11805
|
+
value: draft,
|
|
11806
|
+
placeholder: t("reviewThreadReplyPlaceholder"),
|
|
11807
|
+
suggestLabel: t("reviewThreadMention"),
|
|
11808
|
+
disabled: busy,
|
|
11809
|
+
autoFocus: true,
|
|
11810
|
+
suggest,
|
|
11811
|
+
onChange: setDraft,
|
|
11812
|
+
onSubmit: send
|
|
11813
|
+
}),
|
|
11814
|
+
/* @__PURE__ */ jsxs("div", {
|
|
11815
|
+
style: diffCommentActions,
|
|
11816
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
11817
|
+
type: "button",
|
|
11818
|
+
style: diffCommentActionButton,
|
|
11819
|
+
disabled: busy,
|
|
11820
|
+
onClick: () => {
|
|
11821
|
+
setReplying(false);
|
|
11822
|
+
setError(void 0);
|
|
11823
|
+
},
|
|
11824
|
+
children: t("reviewCommentCancel")
|
|
11825
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
11826
|
+
type: "button",
|
|
11827
|
+
style: {
|
|
11828
|
+
...diffCommentActionButton,
|
|
11829
|
+
...diffCommentSubmitButton
|
|
11830
|
+
},
|
|
11831
|
+
disabled: busy || draft.trim().length === 0,
|
|
11832
|
+
onClick: send,
|
|
11833
|
+
children: t("reviewThreadSend")
|
|
11834
|
+
})]
|
|
11835
|
+
})
|
|
11836
|
+
]
|
|
11837
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
11838
|
+
style: diffCommentActions,
|
|
11839
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
11840
|
+
type: "button",
|
|
11841
|
+
style: diffCommentActionButton,
|
|
11842
|
+
disabled: busy,
|
|
11843
|
+
onClick: () => {
|
|
11844
|
+
setReplying(true);
|
|
11845
|
+
},
|
|
11846
|
+
children: t("reviewThreadReply")
|
|
11847
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
11848
|
+
type: "button",
|
|
11849
|
+
style: diffCommentActionButton,
|
|
11850
|
+
disabled: busy,
|
|
11851
|
+
onClick: toggleResolved,
|
|
11852
|
+
children: thread.resolved ? t("reviewThreadUnresolve") : t("reviewThreadResolve")
|
|
11853
|
+
})]
|
|
11854
|
+
})
|
|
11855
|
+
]
|
|
11152
11856
|
});
|
|
11153
11857
|
}
|
|
11154
|
-
installCommentSanitizerHooks();
|
|
11155
11858
|
//#endregion
|
|
11156
11859
|
//#region src/client/ClaudeDiffPanel.tsx
|
|
11157
11860
|
function pathFromHeader(line) {
|
|
@@ -11304,6 +12007,28 @@ window.__ModuleLoader__.load({
|
|
|
11304
12007
|
}
|
|
11305
12008
|
return out;
|
|
11306
12009
|
}
|
|
12010
|
+
/** Everything in this diff still waiting on the reader, in reading order:
|
|
12011
|
+
* files as the panel lists them, lines as the file reads. Resolved threads are
|
|
12012
|
+
* collapsed by design, and a comment on a file this diff does not render has
|
|
12013
|
+
* nowhere to scroll to, so neither is a stop. */
|
|
12014
|
+
function reviewTargets(files, comments, threads) {
|
|
12015
|
+
const targets = [];
|
|
12016
|
+
for (const file of files) {
|
|
12017
|
+
const inFile = [...threads.filter((thread) => thread.path === file.path && !thread.resolved && thread.line !== void 0).map((thread) => ({
|
|
12018
|
+
key: `thread:${thread.id}`,
|
|
12019
|
+
path: thread.path,
|
|
12020
|
+
line: thread.line ?? 0,
|
|
12021
|
+
side: thread.side
|
|
12022
|
+
})), ...comments.filter((comment) => comment.path === file.path).map((comment) => ({
|
|
12023
|
+
key: `comment:${comment.id}`,
|
|
12024
|
+
path: comment.path,
|
|
12025
|
+
line: comment.line,
|
|
12026
|
+
side: comment.side
|
|
12027
|
+
}))];
|
|
12028
|
+
targets.push(...inFile.sort((left, right) => left.line - right.line || left.side.localeCompare(right.side)));
|
|
12029
|
+
}
|
|
12030
|
+
return targets;
|
|
12031
|
+
}
|
|
11307
12032
|
/**
|
|
11308
12033
|
* Anchor for a drag from row `from` to row `to`: every commentable row in
|
|
11309
12034
|
* between on the same side as the first row, collapsed to its first/last line.
|
|
@@ -11430,8 +12155,7 @@ window.__ModuleLoader__.load({
|
|
|
11430
12155
|
children: /* @__PURE__ */ jsx("path", { d: "M14 9.5a2 2 0 0 1-2 2H6l-3.5 2.5V4a2 2 0 0 1 2-2h7.5a2 2 0 0 1 2 2z" })
|
|
11431
12156
|
});
|
|
11432
12157
|
}
|
|
11433
|
-
function DiffFileSection({ file, root,
|
|
11434
|
-
const [open, setOpen] = useState(initiallyOpen);
|
|
12158
|
+
function DiffFileSection({ file, root, open, t, comments, ghThreads, editorAnchor, editorNode, now, activeTargetKey, suggestMention, onOpenEditor, onOpenChange, onRemoveComment, onReplyToThread, onThreadResolvedChange }) {
|
|
11435
12159
|
const [revealed, setRevealed] = useState(() => /* @__PURE__ */ new Map());
|
|
11436
12160
|
const [total, setTotal] = useState();
|
|
11437
12161
|
const [expanding, setExpanding] = useState(false);
|
|
@@ -11443,7 +12167,7 @@ window.__ModuleLoader__.load({
|
|
|
11443
12167
|
]);
|
|
11444
12168
|
const anchors = useMemo(() => rows.map(commentAnchorForLine), [rows]);
|
|
11445
12169
|
const name = file.path.slice(file.path.lastIndexOf("/") + 1);
|
|
11446
|
-
const commentCount = comments.length +
|
|
12170
|
+
const commentCount = comments.length + ghThreads.reduce((total, thread) => total + thread.comments.length, 0);
|
|
11447
12171
|
const expand = (gap, direction) => {
|
|
11448
12172
|
if (root === void 0 || expanding) return;
|
|
11449
12173
|
const span = gap.count ?? 20;
|
|
@@ -11486,14 +12210,16 @@ window.__ModuleLoader__.load({
|
|
|
11486
12210
|
type: "button",
|
|
11487
12211
|
style: diffFileHeader,
|
|
11488
12212
|
"aria-expanded": open,
|
|
11489
|
-
onClick: () =>
|
|
12213
|
+
onClick: () => onOpenChange(!open),
|
|
11490
12214
|
children: [
|
|
11491
12215
|
/* @__PURE__ */ jsx("span", {
|
|
12216
|
+
"data-diff-file-chevron": "",
|
|
11492
12217
|
style: {
|
|
11493
|
-
...
|
|
12218
|
+
...diffFileChevron,
|
|
11494
12219
|
...open ? chevronOpen : {}
|
|
11495
12220
|
},
|
|
11496
|
-
|
|
12221
|
+
"aria-hidden": "true",
|
|
12222
|
+
children: /* @__PURE__ */ jsx(IconChevronRightOutline14, { size: 14 })
|
|
11497
12223
|
}),
|
|
11498
12224
|
/* @__PURE__ */ jsx("span", {
|
|
11499
12225
|
style: diffFilePath,
|
|
@@ -11536,7 +12262,7 @@ window.__ModuleLoader__.load({
|
|
|
11536
12262
|
}, `gap:${entry.gap.newStart}`);
|
|
11537
12263
|
const anchor = anchors[index];
|
|
11538
12264
|
const lineComments = anchor === void 0 ? [] : comments.filter((comment) => comment.line === anchor.line && comment.side === anchor.side);
|
|
11539
|
-
const
|
|
12265
|
+
const lineThreads = anchor === void 0 ? [] : ghThreads.filter((thread) => thread.line === anchor.line && thread.side === anchor.side);
|
|
11540
12266
|
const editorOpen = anchor !== void 0 && editorAnchor !== void 0 && editorAnchor.line === anchor.line && editorAnchor.side === anchor.side;
|
|
11541
12267
|
const inDrag = dragLow !== void 0 && dragHigh !== void 0 && index >= dragLow && index <= dragHigh && anchor?.side === dragSide;
|
|
11542
12268
|
const inEditorRange = anchor !== void 0 && editorAnchor !== void 0 && editorAnchor.side === anchor.side && anchor.line <= editorAnchor.line && anchor.line >= (editorAnchor.startLine ?? editorAnchor.line);
|
|
@@ -11556,7 +12282,12 @@ window.__ModuleLoader__.load({
|
|
|
11556
12282
|
})
|
|
11557
12283
|
}),
|
|
11558
12284
|
lineComments.map((comment) => /* @__PURE__ */ jsxs("div", {
|
|
11559
|
-
|
|
12285
|
+
"data-review-target": `comment:${comment.id}`,
|
|
12286
|
+
"data-review-active": activeTargetKey === `comment:${comment.id}` ? "true" : void 0,
|
|
12287
|
+
style: {
|
|
12288
|
+
...diffCommentBlock,
|
|
12289
|
+
...activeTargetKey === `comment:${comment.id}` ? diffCommentBlockActive : {}
|
|
12290
|
+
},
|
|
11560
12291
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
11561
12292
|
style: diffCommentCardMeta,
|
|
11562
12293
|
children: [/* @__PURE__ */ jsx("span", { children: commentLineLabel(comment, t) }), /* @__PURE__ */ jsx("button", {
|
|
@@ -11571,41 +12302,16 @@ window.__ModuleLoader__.load({
|
|
|
11571
12302
|
children: comment.text
|
|
11572
12303
|
})]
|
|
11573
12304
|
}, comment.id)),
|
|
11574
|
-
|
|
11575
|
-
|
|
11576
|
-
|
|
11577
|
-
|
|
11578
|
-
|
|
11579
|
-
|
|
11580
|
-
|
|
11581
|
-
|
|
11582
|
-
|
|
11583
|
-
|
|
11584
|
-
height: 16,
|
|
11585
|
-
loading: "lazy",
|
|
11586
|
-
referrerPolicy: "no-referrer",
|
|
11587
|
-
style: diffGhCommentAvatar,
|
|
11588
|
-
onError: (event) => {
|
|
11589
|
-
event.currentTarget.style.display = "none";
|
|
11590
|
-
}
|
|
11591
|
-
}), /* @__PURE__ */ jsxs("span", {
|
|
11592
|
-
style: diffGhCommentAuthor,
|
|
11593
|
-
children: ["@", comment.author]
|
|
11594
|
-
})]
|
|
11595
|
-
}), /* @__PURE__ */ jsx("a", {
|
|
11596
|
-
href: comment.url,
|
|
11597
|
-
target: "_blank",
|
|
11598
|
-
rel: "noopener noreferrer",
|
|
11599
|
-
style: diffGhCommentLink,
|
|
11600
|
-
"aria-label": comment.url,
|
|
11601
|
-
children: "↗"
|
|
11602
|
-
})]
|
|
11603
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
11604
|
-
style: diffCommentCardText,
|
|
11605
|
-
className: "dshClaudeDiffCommentBody",
|
|
11606
|
-
dangerouslySetInnerHTML: { __html: renderCommentBody(comment.body) }
|
|
11607
|
-
})]
|
|
11608
|
-
}, `gh-${comment.id}`)),
|
|
12305
|
+
lineThreads.map((thread) => /* @__PURE__ */ jsx(ReviewThreadCard, {
|
|
12306
|
+
thread,
|
|
12307
|
+
anchorKey: `thread:${thread.id}`,
|
|
12308
|
+
active: activeTargetKey === `thread:${thread.id}`,
|
|
12309
|
+
t,
|
|
12310
|
+
suggest: suggestMention,
|
|
12311
|
+
now,
|
|
12312
|
+
onReply: (body) => onReplyToThread(thread, body),
|
|
12313
|
+
onResolvedChange: (resolved) => onThreadResolvedChange(thread, resolved)
|
|
12314
|
+
}, thread.id)),
|
|
11609
12315
|
editorOpen ? editorNode : null
|
|
11610
12316
|
] }, `${index}:${entry.line}`);
|
|
11611
12317
|
})
|
|
@@ -11646,6 +12352,7 @@ window.__ModuleLoader__.load({
|
|
|
11646
12352
|
const diff = repository?.diff;
|
|
11647
12353
|
const files = useMemo(() => parseUnifiedDiff(diff?.patch ?? ""), [diff?.patch]);
|
|
11648
12354
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
12355
|
+
const { toast, report } = useActionToast();
|
|
11649
12356
|
const [dialog, setDialog] = useState();
|
|
11650
12357
|
const [message, setMessage] = useState("");
|
|
11651
12358
|
const [includeUnstaged, setIncludeUnstaged] = useState(true);
|
|
@@ -11660,21 +12367,55 @@ window.__ModuleLoader__.load({
|
|
|
11660
12367
|
const [localComments, setLocalComments] = useState([]);
|
|
11661
12368
|
const [removedCommentIds, setRemovedCommentIds] = useState(() => /* @__PURE__ */ new Set());
|
|
11662
12369
|
const actionController = useRef();
|
|
11663
|
-
const [
|
|
12370
|
+
const [ghThreads, setGhThreads] = useState([]);
|
|
12371
|
+
const [threadsLoadedAt, setThreadsLoadedAt] = useState(() => Date.now());
|
|
11664
12372
|
const pullNumber = repository?.pullRequest?.state === "open" ? repository.pullRequest.number : void 0;
|
|
11665
12373
|
useEffect(() => {
|
|
11666
|
-
|
|
12374
|
+
setGhThreads([]);
|
|
11667
12375
|
if (pullNumber === void 0) return;
|
|
11668
12376
|
const controller = new AbortController();
|
|
11669
|
-
|
|
12377
|
+
loadPullRequestThreads(sessionId, pullNumber, controller.signal).then((threads) => {
|
|
12378
|
+
setGhThreads(threads);
|
|
12379
|
+
setThreadsLoadedAt(Date.now());
|
|
12380
|
+
}, () => void 0);
|
|
11670
12381
|
return () => {
|
|
11671
12382
|
controller.abort();
|
|
11672
12383
|
};
|
|
11673
12384
|
}, [pullNumber, sessionId]);
|
|
12385
|
+
const openThreadCount = ghThreads.filter((thread) => !thread.resolved).length;
|
|
12386
|
+
const bodyRef = useRef(null);
|
|
12387
|
+
const [targetIndex, setTargetIndex] = useState(0);
|
|
12388
|
+
const [activeTargetKey, setActiveTargetKey] = useState();
|
|
12389
|
+
const [pendingScrollKey, setPendingScrollKey] = useState();
|
|
12390
|
+
const [openFiles, setOpenFiles] = useState(() => /* @__PURE__ */ new Map());
|
|
12391
|
+
const fileOpen = useCallback((path, index) => openFiles.get(path) ?? index === 0, [openFiles]);
|
|
12392
|
+
const setFileOpen = useCallback((path, open) => {
|
|
12393
|
+
setOpenFiles((current) => new Map(current).set(path, open));
|
|
12394
|
+
}, []);
|
|
12395
|
+
const suggestMention = useCallback(async (query) => pullNumber === void 0 ? [] : loadMentionableUsers(sessionId, pullNumber, query).catch(() => []), [pullNumber, sessionId]);
|
|
12396
|
+
const replyToThread = useCallback(async (thread, body) => {
|
|
12397
|
+
if (pullNumber === void 0) return;
|
|
12398
|
+
const anchor = thread.comments[0];
|
|
12399
|
+
if (anchor === void 0) return;
|
|
12400
|
+
const posted = await replyToReviewThread(sessionId, pullNumber, anchor.id, body);
|
|
12401
|
+
setGhThreads((list) => list.map((item) => item.id === thread.id ? {
|
|
12402
|
+
...item,
|
|
12403
|
+
comments: [...item.comments, posted]
|
|
12404
|
+
} : item));
|
|
12405
|
+
}, [pullNumber, sessionId]);
|
|
12406
|
+
const changeThreadResolved = useCallback(async (thread, resolved) => {
|
|
12407
|
+
if (pullNumber === void 0) return;
|
|
12408
|
+
const state = await setReviewThreadResolved(sessionId, pullNumber, thread.id, resolved);
|
|
12409
|
+
setGhThreads((list) => list.map((item) => item.id === thread.id ? {
|
|
12410
|
+
...item,
|
|
12411
|
+
resolved: state
|
|
12412
|
+
} : item));
|
|
12413
|
+
}, [pullNumber, sessionId]);
|
|
11674
12414
|
const diffViewportObserver = useRef();
|
|
11675
12415
|
const diffBodyRef = useCallback((element) => {
|
|
11676
12416
|
diffViewportObserver.current?.disconnect();
|
|
11677
12417
|
diffViewportObserver.current = void 0;
|
|
12418
|
+
bodyRef.current = element;
|
|
11678
12419
|
if (element === null || typeof ResizeObserver === "undefined") return;
|
|
11679
12420
|
const update = () => element.style.setProperty("--dsh-claude-diff-viewport", `${element.clientWidth}px`);
|
|
11680
12421
|
update();
|
|
@@ -11689,16 +12430,6 @@ window.__ModuleLoader__.load({
|
|
|
11689
12430
|
actionController.current = void 0;
|
|
11690
12431
|
setDialog(void 0);
|
|
11691
12432
|
}, [dialog?.submitting]);
|
|
11692
|
-
useEffect(() => {
|
|
11693
|
-
if (dialog?.commit === void 0 || dialog.error !== void 0 || dialog.pullRequestUrl !== void 0) return;
|
|
11694
|
-
const timer = setTimeout(closeDialog, 1200);
|
|
11695
|
-
return () => clearTimeout(timer);
|
|
11696
|
-
}, [
|
|
11697
|
-
closeDialog,
|
|
11698
|
-
dialog?.commit,
|
|
11699
|
-
dialog?.error,
|
|
11700
|
-
dialog?.pullRequestUrl
|
|
11701
|
-
]);
|
|
11702
12433
|
const openAction = useCallback((action) => {
|
|
11703
12434
|
actionController.current?.abort();
|
|
11704
12435
|
setMenuOpen(false);
|
|
@@ -11732,14 +12463,12 @@ window.__ModuleLoader__.load({
|
|
|
11732
12463
|
submitting: false
|
|
11733
12464
|
});
|
|
11734
12465
|
const generated = await generateCommitMessage(sessionId, preview.fingerprint, controller.signal);
|
|
11735
|
-
setMessage(generated);
|
|
11736
|
-
setPrTitle(generated);
|
|
11737
|
-
setPrBody(`Summary: ${generated}\n\nChanges:\n- ${generated}`);
|
|
11738
|
-
setDialog({
|
|
11739
|
-
|
|
11740
|
-
|
|
11741
|
-
loading: false,
|
|
11742
|
-
submitting: false
|
|
12466
|
+
setMessage((current) => current.trim() === "" ? generated : current);
|
|
12467
|
+
setPrTitle((current) => current.trim() === "" ? generated : current);
|
|
12468
|
+
setPrBody((current) => current.trim() === "" ? `Summary: ${generated}\n\nChanges:\n- ${generated}` : current);
|
|
12469
|
+
setDialog((current) => current === void 0 ? current : {
|
|
12470
|
+
...current,
|
|
12471
|
+
loading: false
|
|
11743
12472
|
});
|
|
11744
12473
|
}).catch((error) => {
|
|
11745
12474
|
if (!controller.signal.aborted) setDialog({
|
|
@@ -11770,12 +12499,8 @@ window.__ModuleLoader__.load({
|
|
|
11770
12499
|
draft
|
|
11771
12500
|
} : {}
|
|
11772
12501
|
});
|
|
11773
|
-
|
|
11774
|
-
|
|
11775
|
-
submitting: false,
|
|
11776
|
-
commit: result.commit,
|
|
11777
|
-
...result.pullRequestUrl === void 0 ? {} : { pullRequestUrl: result.pullRequestUrl }
|
|
11778
|
-
});
|
|
12502
|
+
report(result.pullRequestUrl === void 0 ? t(dialog.action === "push" ? "diffPushCompleted" : "diffCommitCompleted", { commit: result.commit.slice(0, 8) }) : t("diffPrCompleted"));
|
|
12503
|
+
setDialog(void 0);
|
|
11779
12504
|
} catch (error) {
|
|
11780
12505
|
const completedCommit = typeof error === "object" && error !== null && "commit" in error && typeof error.commit === "string" ? error.commit : void 0;
|
|
11781
12506
|
setDialog({
|
|
@@ -11793,6 +12518,7 @@ window.__ModuleLoader__.load({
|
|
|
11793
12518
|
message,
|
|
11794
12519
|
prBody,
|
|
11795
12520
|
prTitle,
|
|
12521
|
+
report,
|
|
11796
12522
|
sessionId,
|
|
11797
12523
|
t
|
|
11798
12524
|
]);
|
|
@@ -11865,6 +12591,47 @@ window.__ModuleLoader__.load({
|
|
|
11865
12591
|
projection.reviewComments,
|
|
11866
12592
|
removedCommentIds
|
|
11867
12593
|
]);
|
|
12594
|
+
const targets = useMemo(() => reviewTargets(files, reviewComments, ghThreads), [
|
|
12595
|
+
files,
|
|
12596
|
+
ghThreads,
|
|
12597
|
+
reviewComments
|
|
12598
|
+
]);
|
|
12599
|
+
useEffect(() => {
|
|
12600
|
+
setTargetIndex((index) => index < targets.length ? index : 0);
|
|
12601
|
+
}, [targets.length]);
|
|
12602
|
+
const goToComment = useCallback((direction) => {
|
|
12603
|
+
setTargetIndex((current) => {
|
|
12604
|
+
if (targets.length === 0) return current;
|
|
12605
|
+
const next = menuNavigationIndex(current, targets.length, direction);
|
|
12606
|
+
const target = targets[next];
|
|
12607
|
+
if (target !== void 0) {
|
|
12608
|
+
setActiveTargetKey(target.key);
|
|
12609
|
+
setPendingScrollKey(target.key);
|
|
12610
|
+
setFileOpen(target.path, true);
|
|
12611
|
+
}
|
|
12612
|
+
return next;
|
|
12613
|
+
});
|
|
12614
|
+
}, [setFileOpen, targets]);
|
|
12615
|
+
useEffect(() => {
|
|
12616
|
+
if (pendingScrollKey === void 0) return;
|
|
12617
|
+
bodyRef.current?.querySelector(`[data-review-target="${pendingScrollKey}"]`)?.scrollIntoView({ block: "center" });
|
|
12618
|
+
setPendingScrollKey(void 0);
|
|
12619
|
+
}, [pendingScrollKey]);
|
|
12620
|
+
useEffect(() => {
|
|
12621
|
+
if (targets.length === 0) return;
|
|
12622
|
+
const shortcut = (event) => {
|
|
12623
|
+
if (event.ctrlKey || event.metaKey || event.altKey) return;
|
|
12624
|
+
const origin = event.target;
|
|
12625
|
+
if (origin instanceof HTMLElement && (origin.isContentEditable || origin.tagName === "INPUT" || origin.tagName === "TEXTAREA" || origin.tagName === "SELECT")) return;
|
|
12626
|
+
if (event.key !== "n" && event.key !== "p") return;
|
|
12627
|
+
event.preventDefault();
|
|
12628
|
+
goToComment(event.key === "n" ? "ArrowDown" : "ArrowUp");
|
|
12629
|
+
};
|
|
12630
|
+
document.addEventListener("keydown", shortcut);
|
|
12631
|
+
return () => {
|
|
12632
|
+
document.removeEventListener("keydown", shortcut);
|
|
12633
|
+
};
|
|
12634
|
+
}, [goToComment, targets.length]);
|
|
11868
12635
|
useEffect(() => () => actionController.current?.abort(), []);
|
|
11869
12636
|
useEffect(() => {
|
|
11870
12637
|
if (!projection.owned || repository?.status !== "ready" || diff === void 0) closeDetails();
|
|
@@ -11900,7 +12667,7 @@ window.__ModuleLoader__.load({
|
|
|
11900
12667
|
disabled: !availability["create-pr"]
|
|
11901
12668
|
}
|
|
11902
12669
|
];
|
|
11903
|
-
const
|
|
12670
|
+
const allFilesOpen = files.every((file, index) => fileOpen(file.path, index));
|
|
11904
12671
|
const commentEditorNode = commentEditor === void 0 ? null : /* @__PURE__ */ jsxs("div", {
|
|
11905
12672
|
style: diffCommentBlock,
|
|
11906
12673
|
children: [
|
|
@@ -11942,6 +12709,7 @@ window.__ModuleLoader__.load({
|
|
|
11942
12709
|
]
|
|
11943
12710
|
});
|
|
11944
12711
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
12712
|
+
toast,
|
|
11945
12713
|
/* @__PURE__ */ jsxs("style", {
|
|
11946
12714
|
"data-dsh-claude-repository-modal-styles": true,
|
|
11947
12715
|
children: [
|
|
@@ -12014,12 +12782,46 @@ window.__ModuleLoader__.load({
|
|
|
12014
12782
|
})
|
|
12015
12783
|
})]
|
|
12016
12784
|
}),
|
|
12017
|
-
|
|
12785
|
+
targets.length === 0 ? null : /* @__PURE__ */ jsxs("div", {
|
|
12786
|
+
style: diffCommentNav,
|
|
12787
|
+
children: [
|
|
12788
|
+
/* @__PURE__ */ jsx("button", {
|
|
12789
|
+
type: "button",
|
|
12790
|
+
className: panelIconButtonClass,
|
|
12791
|
+
"aria-label": t("diffCommentPrevious"),
|
|
12792
|
+
title: t("diffCommentPosition", {
|
|
12793
|
+
index: targetIndex + 1,
|
|
12794
|
+
total: targets.length
|
|
12795
|
+
}),
|
|
12796
|
+
onClick: () => goToComment("ArrowUp"),
|
|
12797
|
+
children: /* @__PURE__ */ jsx(IconChevronUpOutline14, {})
|
|
12798
|
+
}),
|
|
12799
|
+
/* @__PURE__ */ jsx("span", {
|
|
12800
|
+
style: diffCommentNavCount,
|
|
12801
|
+
children: t("diffCommentCounter", {
|
|
12802
|
+
index: targetIndex + 1,
|
|
12803
|
+
total: targets.length
|
|
12804
|
+
})
|
|
12805
|
+
}),
|
|
12806
|
+
/* @__PURE__ */ jsx("button", {
|
|
12807
|
+
type: "button",
|
|
12808
|
+
className: panelIconButtonClass,
|
|
12809
|
+
"aria-label": t("diffCommentNext"),
|
|
12810
|
+
title: t("diffCommentPosition", {
|
|
12811
|
+
index: targetIndex + 1,
|
|
12812
|
+
total: targets.length
|
|
12813
|
+
}),
|
|
12814
|
+
onClick: () => goToComment("ArrowDown"),
|
|
12815
|
+
children: /* @__PURE__ */ jsx(IconChevronDownOutline14, {})
|
|
12816
|
+
})
|
|
12817
|
+
]
|
|
12818
|
+
}),
|
|
12819
|
+
openThreadCount > 0 && submitPrompt !== void 0 ? /* @__PURE__ */ jsxs("button", {
|
|
12018
12820
|
type: "button",
|
|
12019
12821
|
style: diffPrCommentsButton,
|
|
12020
12822
|
title: t("prCommentsSend"),
|
|
12021
|
-
"aria-label": t("prCommentsButton", { count:
|
|
12022
|
-
onClick: () => submitPrompt(composeCommentsPrompt(
|
|
12823
|
+
"aria-label": t("prCommentsButton", { count: openThreadCount }),
|
|
12824
|
+
onClick: () => submitPrompt(composeCommentsPrompt(ghThreads)),
|
|
12023
12825
|
children: [/* @__PURE__ */ jsx("svg", {
|
|
12024
12826
|
width: "14",
|
|
12025
12827
|
height: "14",
|
|
@@ -12031,7 +12833,7 @@ window.__ModuleLoader__.load({
|
|
|
12031
12833
|
strokeLinejoin: "round",
|
|
12032
12834
|
"aria-hidden": "true",
|
|
12033
12835
|
children: /* @__PURE__ */ jsx("path", { d: "M2.75 2.75h10.5a1 1 0 0 1 1 1v6.5a1 1 0 0 1-1 1H8.2l-3.2 2.9v-2.9H2.75a1 1 0 0 1-1-1v-6.5a1 1 0 0 1 1-1Z" })
|
|
12034
|
-
}),
|
|
12836
|
+
}), openThreadCount]
|
|
12035
12837
|
}) : null,
|
|
12036
12838
|
/* @__PURE__ */ jsx("button", {
|
|
12037
12839
|
type: "button",
|
|
@@ -12061,6 +12863,15 @@ window.__ModuleLoader__.load({
|
|
|
12061
12863
|
/* @__PURE__ */ jsxs("span", {
|
|
12062
12864
|
style: diffDelete,
|
|
12063
12865
|
children: ["−", diff.deletions]
|
|
12866
|
+
}),
|
|
12867
|
+
files.length === 0 ? null : /* @__PURE__ */ jsx("button", {
|
|
12868
|
+
type: "button",
|
|
12869
|
+
style: diffSummaryAction,
|
|
12870
|
+
"aria-label": allFilesOpen ? t("diffCollapseAll") : t("diffExpandAll"),
|
|
12871
|
+
onClick: () => {
|
|
12872
|
+
setOpenFiles(new Map(files.map((file) => [file.path, !allFilesOpen])));
|
|
12873
|
+
},
|
|
12874
|
+
children: allFilesOpen ? t("diffCollapseAll") : t("diffExpandAll")
|
|
12064
12875
|
})
|
|
12065
12876
|
]
|
|
12066
12877
|
}),
|
|
@@ -12076,10 +12887,18 @@ window.__ModuleLoader__.load({
|
|
|
12076
12887
|
}) : files.map((file, index) => /* @__PURE__ */ jsx(DiffFileSection, {
|
|
12077
12888
|
file,
|
|
12078
12889
|
root: repository.root,
|
|
12079
|
-
|
|
12890
|
+
open: fileOpen(file.path, index),
|
|
12891
|
+
onOpenChange: (open) => {
|
|
12892
|
+
setFileOpen(file.path, open);
|
|
12893
|
+
},
|
|
12080
12894
|
t,
|
|
12081
12895
|
comments: reviewComments.filter((comment) => comment.path === file.path),
|
|
12082
|
-
|
|
12896
|
+
ghThreads: ghThreads.filter((thread) => thread.path === file.path),
|
|
12897
|
+
suggestMention,
|
|
12898
|
+
now: threadsLoadedAt,
|
|
12899
|
+
activeTargetKey,
|
|
12900
|
+
onReplyToThread: replyToThread,
|
|
12901
|
+
onThreadResolvedChange: changeThreadResolved,
|
|
12083
12902
|
editorAnchor: commentEditor !== void 0 && commentEditor.path === file.path ? commentEditor : void 0,
|
|
12084
12903
|
editorNode: commentEditorNode,
|
|
12085
12904
|
onOpenEditor: (anchor) => openCommentEditor(file.path, anchor),
|
|
@@ -12106,17 +12925,17 @@ window.__ModuleLoader__.load({
|
|
|
12106
12925
|
},
|
|
12107
12926
|
disabled: dialog?.submitting === true,
|
|
12108
12927
|
onClick: closeDialog,
|
|
12109
|
-
children:
|
|
12110
|
-
}),
|
|
12928
|
+
children: t("diffCancel")
|
|
12929
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
12111
12930
|
type: "button",
|
|
12112
12931
|
style: {
|
|
12113
12932
|
...primaryButton,
|
|
12114
12933
|
...diffModalButton
|
|
12115
12934
|
},
|
|
12116
|
-
disabled: dialog?.
|
|
12935
|
+
disabled: dialog?.submitting === true || dialog?.preview === void 0 || dialog.action !== "push" && message.trim() === "",
|
|
12117
12936
|
onClick: () => void confirm(),
|
|
12118
12937
|
children: dialog?.submitting === true ? t("diffSubmitting") : t("diffConfirm")
|
|
12119
|
-
})
|
|
12938
|
+
})]
|
|
12120
12939
|
}),
|
|
12121
12940
|
children: [
|
|
12122
12941
|
dialog?.loading === true ? /* @__PURE__ */ jsx("p", {
|
|
@@ -12227,17 +13046,7 @@ window.__ModuleLoader__.load({
|
|
|
12227
13046
|
onChange: (event) => setDraft(event.currentTarget.checked)
|
|
12228
13047
|
}), t("diffPrDraft")]
|
|
12229
13048
|
})
|
|
12230
|
-
] }) : null
|
|
12231
|
-
dialog.commit !== void 0 ? /* @__PURE__ */ jsx("p", {
|
|
12232
|
-
style: diffModalSuccess,
|
|
12233
|
-
children: dialog.action === "push" ? t("diffPushCompleted", { commit: dialog.commit.slice(0, 8) }) : t("diffCommitCompleted", { commit: dialog.commit.slice(0, 8) })
|
|
12234
|
-
}) : null,
|
|
12235
|
-
dialog.pullRequestUrl !== void 0 ? /* @__PURE__ */ jsx("a", {
|
|
12236
|
-
href: dialog.pullRequestUrl,
|
|
12237
|
-
target: "_blank",
|
|
12238
|
-
rel: "noopener noreferrer",
|
|
12239
|
-
children: t("diffOpenPr")
|
|
12240
|
-
}) : null
|
|
13049
|
+
] }) : null
|
|
12241
13050
|
]
|
|
12242
13051
|
}) : null,
|
|
12243
13052
|
dialog?.error !== void 0 ? /* @__PURE__ */ jsxs("p", {
|
|
@@ -12553,8 +13362,18 @@ window.__ModuleLoader__.load({
|
|
|
12553
13362
|
] });
|
|
12554
13363
|
}
|
|
12555
13364
|
function ClaudePullRequestsPanel({ t, closeDetails, openSession, loadStatus, sessions, workspaces, projectionFor }) {
|
|
12556
|
-
const
|
|
12557
|
-
|
|
13365
|
+
const sessionStore = useMemo(() => ({
|
|
13366
|
+
subscribe: (listener) => sessions.subscribe(listener),
|
|
13367
|
+
getSnapshot: () => sessions.getSnapshot()
|
|
13368
|
+
}), [sessions]);
|
|
13369
|
+
const snapshot = useSyncExternalStore(sessionStore.subscribe, sessionStore.getSnapshot, sessionStore.getSnapshot);
|
|
13370
|
+
const workspaceStore = useMemo(() => {
|
|
13371
|
+
const source = workspaces ?? NO_WORKSPACES;
|
|
13372
|
+
return {
|
|
13373
|
+
subscribe: (listener) => source.subscribe(listener),
|
|
13374
|
+
getSnapshot: () => source.getSnapshot()
|
|
13375
|
+
};
|
|
13376
|
+
}, [workspaces]);
|
|
12558
13377
|
const workspaceState = useSyncExternalStore(workspaceStore.subscribe, workspaceStore.getSnapshot, workspaceStore.getSnapshot);
|
|
12559
13378
|
const rows = useMemo(() => claudeSessionRows(snapshot, workspaceState.archivedSessionIds ?? []), [snapshot, workspaceState]);
|
|
12560
13379
|
const cwdKey = useMemo(() => [...new Set(rows.map((row) => row.cwd ?? ""))].sort().join("\0"), [rows]);
|
|
@@ -12915,6 +13734,7 @@ window.__ModuleLoader__.load({
|
|
|
12915
13734
|
/** Selection toolbar over assistant replies: copy, or ask a follow-up whose
|
|
12916
13735
|
* answer streams into a popup rendered with the Host Markdown renderer. */
|
|
12917
13736
|
function ClaudeSelectionAsk({ t, currentSessionId, ownsSession, insertIntoChat }) {
|
|
13737
|
+
const markdownLabels = useClaudeMarkdownLabels(t);
|
|
12918
13738
|
const [selection, setSelection] = useState();
|
|
12919
13739
|
const [open, setOpen] = useState(false);
|
|
12920
13740
|
const [question, setQuestion] = useState("");
|
|
@@ -13196,8 +14016,9 @@ window.__ModuleLoader__.load({
|
|
|
13196
14016
|
style: askStatus,
|
|
13197
14017
|
children: started ? t("askThinking") : t("askStarting")
|
|
13198
14018
|
}) : null,
|
|
13199
|
-
blocks.map((block, index) => block.kind === "text" ? /* @__PURE__ */ jsx(
|
|
14019
|
+
blocks.map((block, index) => block.kind === "text" ? /* @__PURE__ */ jsx(ClaudeMarkdown, {
|
|
13200
14020
|
text: block.text,
|
|
14021
|
+
labels: markdownLabels,
|
|
13201
14022
|
streaming: phase === "answering" && index === blocks.length - 1
|
|
13202
14023
|
}, `text-${index}`) : /* @__PURE__ */ jsxs("div", {
|
|
13203
14024
|
style: askToolRow,
|
|
@@ -13263,6 +14084,77 @@ window.__ModuleLoader__.load({
|
|
|
13263
14084
|
});
|
|
13264
14085
|
}
|
|
13265
14086
|
//#endregion
|
|
14087
|
+
//#region src/client/composer-style-probe.ts
|
|
14088
|
+
/** Watch for the plugin's composer bar and check it once for style drift.
|
|
14089
|
+
*
|
|
14090
|
+
* The Host publishes the composer layout properties onto the composer subtree,
|
|
14091
|
+
* not onto `:root`. Custom properties inherit, so only an element inside that
|
|
14092
|
+
* subtree can read one — probing the document root reports every one of them
|
|
14093
|
+
* missing whether or not the Host still defines it, which is exactly the
|
|
14094
|
+
* false alarm this replaced.
|
|
14095
|
+
*
|
|
14096
|
+
* The bar exists only while a Session is on screen, so this waits rather than
|
|
14097
|
+
* sampling once at boot, and stops after the first successful read: the answer
|
|
14098
|
+
* cannot change without a Host reload.
|
|
14099
|
+
*
|
|
14100
|
+
* @param report - receives one line per property the bar cannot see.
|
|
14101
|
+
* @returns disposer; safe to call more than once.
|
|
14102
|
+
*/
|
|
14103
|
+
function watchClaudeComposerBar(report) {
|
|
14104
|
+
if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => {};
|
|
14105
|
+
let observer;
|
|
14106
|
+
const stop = () => {
|
|
14107
|
+
observer?.disconnect();
|
|
14108
|
+
observer = void 0;
|
|
14109
|
+
};
|
|
14110
|
+
const probe = () => {
|
|
14111
|
+
const bar = document.querySelector(`[${CLAUDE_COMPOSER_BAR_ATTRIBUTE}]`);
|
|
14112
|
+
if (bar === null) return false;
|
|
14113
|
+
const style = getComputedStyle(bar);
|
|
14114
|
+
for (const finding of claudeScopedCssFindings((name) => style.getPropertyValue(name))) report(finding);
|
|
14115
|
+
return true;
|
|
14116
|
+
};
|
|
14117
|
+
if (probe()) return stop;
|
|
14118
|
+
observer = new MutationObserver(() => {
|
|
14119
|
+
if (probe()) stop();
|
|
14120
|
+
});
|
|
14121
|
+
observer.observe(document.body, {
|
|
14122
|
+
childList: true,
|
|
14123
|
+
subtree: true
|
|
14124
|
+
});
|
|
14125
|
+
return stop;
|
|
14126
|
+
}
|
|
14127
|
+
function postToHost(report) {
|
|
14128
|
+
fetch(CLAUDE_CLIENT_DIAGNOSTICS_PATH, {
|
|
14129
|
+
method: "POST",
|
|
14130
|
+
credentials: "same-origin",
|
|
14131
|
+
headers: { "content-type": "application/json" },
|
|
14132
|
+
body: JSON.stringify(report)
|
|
14133
|
+
}).catch(() => {});
|
|
14134
|
+
}
|
|
14135
|
+
/** Renderer-side findings reach the Host log through here.
|
|
14136
|
+
*
|
|
14137
|
+
* Nothing the renderer throws — a crashed Slot entry included — reaches the
|
|
14138
|
+
* Host log on its own, and the shipped Desktop build opens no DevTools, so a
|
|
14139
|
+
* plugin whose entries all died looks exactly like a healthy one from the
|
|
14140
|
+
* outside. Every Desktop 2.0 breakage in this package was found only by
|
|
14141
|
+
* attaching a debugger to the renderer by hand. */
|
|
14142
|
+
function createClaudeDiagnosticsReporter(post = postToHost) {
|
|
14143
|
+
const sent = /* @__PURE__ */ new Set();
|
|
14144
|
+
return { report(kind, detail) {
|
|
14145
|
+
if (sent.size >= 40) return;
|
|
14146
|
+
const key = `${kind} ${detail}`;
|
|
14147
|
+
if (sent.has(key)) return;
|
|
14148
|
+
sent.add(key);
|
|
14149
|
+
try {
|
|
14150
|
+
post({
|
|
14151
|
+
kind,
|
|
14152
|
+
detail
|
|
14153
|
+
});
|
|
14154
|
+
} catch {}
|
|
14155
|
+
} };
|
|
14156
|
+
}
|
|
14157
|
+
//#endregion
|
|
13266
14158
|
//#region src/client/rewind-dom.ts
|
|
13267
14159
|
/** Seats for the rewind control inside the Host's own message action rows.
|
|
13268
14160
|
*
|
|
@@ -13346,7 +14238,7 @@ window.__ModuleLoader__.load({
|
|
|
13346
14238
|
//#endregion
|
|
13347
14239
|
//#region src/client/ClaudeRewind.tsx
|
|
13348
14240
|
const EMPTY_RANGES = [];
|
|
13349
|
-
const
|
|
14241
|
+
const EMPTY_CHAT_VIEW = {
|
|
13350
14242
|
chat: {
|
|
13351
14243
|
order: [],
|
|
13352
14244
|
nodes: { get: () => void 0 }
|
|
@@ -13354,7 +14246,7 @@ window.__ModuleLoader__.load({
|
|
|
13354
14246
|
running: false
|
|
13355
14247
|
};
|
|
13356
14248
|
const NO_SUBSCRIBE = () => () => {};
|
|
13357
|
-
const EMPTY_CHAT_SNAPSHOT = () =>
|
|
14249
|
+
const EMPTY_CHAT_SNAPSHOT = () => EMPTY_CHAT_VIEW;
|
|
13358
14250
|
const EMPTY_PROJECTION_SNAPSHOT = () => EMPTY_CLAUDE_PROJECTION;
|
|
13359
14251
|
/** Plain text of one user message node, matching what the copy action yields. */
|
|
13360
14252
|
function rewindMessageText(data) {
|
|
@@ -13673,12 +14565,6 @@ window.__ModuleLoader__.load({
|
|
|
13673
14565
|
function toggleTicketSelection(tickets, ticket) {
|
|
13674
14566
|
return tickets.some((item) => item.key === ticket.key) ? tickets.filter((item) => item.key !== ticket.key) : [...tickets, ticket];
|
|
13675
14567
|
}
|
|
13676
|
-
function branchMenuNavigationIndex(current, count, key) {
|
|
13677
|
-
if (count <= 0) return 0;
|
|
13678
|
-
if (key === "Home") return 0;
|
|
13679
|
-
if (key === "End") return count - 1;
|
|
13680
|
-
return (current + (key === "ArrowDown" ? 1 : -1) + count) % count;
|
|
13681
|
-
}
|
|
13682
14568
|
const BRANCH_LOAD_RETRIES = 2;
|
|
13683
14569
|
const BRANCH_LOAD_RETRY_MS = 1e3;
|
|
13684
14570
|
const WORKTREE_PROGRESS_STAGES = [
|
|
@@ -13842,7 +14728,7 @@ window.__ModuleLoader__.load({
|
|
|
13842
14728
|
if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Home" || event.key === "End") {
|
|
13843
14729
|
event.preventDefault();
|
|
13844
14730
|
const key = event.key;
|
|
13845
|
-
setActiveIndex((current) =>
|
|
14731
|
+
setActiveIndex((current) => menuNavigationIndex(current, filtered.length, key));
|
|
13846
14732
|
} else if (event.key === "Enter") {
|
|
13847
14733
|
event.preventDefault();
|
|
13848
14734
|
chooseActive();
|
|
@@ -14803,9 +15689,9 @@ window.__ModuleLoader__.load({
|
|
|
14803
15689
|
if (this.#inflight !== void 0) return;
|
|
14804
15690
|
this.#inflight = (async () => {
|
|
14805
15691
|
try {
|
|
14806
|
-
const response = await this.#api.list(
|
|
14807
|
-
if (!response.
|
|
14808
|
-
this.#rows = response.
|
|
15692
|
+
const response = await this.#api.list();
|
|
15693
|
+
if (!response.ok) return;
|
|
15694
|
+
this.#rows = response.value.presets;
|
|
14809
15695
|
for (const listener of this.#listeners) listener();
|
|
14810
15696
|
} catch {} finally {
|
|
14811
15697
|
this.#inflight = void 0;
|
|
@@ -15248,6 +16134,9 @@ window.__ModuleLoader__.load({
|
|
|
15248
16134
|
toolInput: "输入",
|
|
15249
16135
|
toolOutput: "输出",
|
|
15250
16136
|
toolError: "错误",
|
|
16137
|
+
markdownCopy: "复制",
|
|
16138
|
+
markdownCopied: "已复制",
|
|
16139
|
+
markdownFootnotes: "脚注",
|
|
15251
16140
|
tokens: "{count} 个 token",
|
|
15252
16141
|
doctor: "运行诊断",
|
|
15253
16142
|
refreshing: "诊断中…",
|
|
@@ -15420,6 +16309,12 @@ window.__ModuleLoader__.load({
|
|
|
15420
16309
|
diffTruncated: "Diff 超出安全显示上限。请在终端中查看完整内容。",
|
|
15421
16310
|
diffEmpty: "没有可显示的 tracked 文件改动",
|
|
15422
16311
|
diffMaximize: "最大化 Diff 面板",
|
|
16312
|
+
diffCommentPrevious: "上一条评论",
|
|
16313
|
+
diffCommentNext: "下一条评论",
|
|
16314
|
+
diffCommentPosition: "第 {index} 条,共 {total} 条",
|
|
16315
|
+
diffCommentCounter: "{index}/{total}",
|
|
16316
|
+
diffExpandAll: "展开全部文件",
|
|
16317
|
+
diffCollapseAll: "收起全部文件",
|
|
15423
16318
|
diffRestore: "还原 Diff 面板",
|
|
15424
16319
|
diffCommit: "Commit",
|
|
15425
16320
|
diffCommitMenu: "打开提交操作菜单",
|
|
@@ -15430,7 +16325,7 @@ window.__ModuleLoader__.load({
|
|
|
15430
16325
|
diffPushDescription: "将本地未推送的 commit 推送到远端分支。",
|
|
15431
16326
|
diffPushAhead: "{count} 个未推送的 commit",
|
|
15432
16327
|
diffPushCompleted: "已推送 commit {commit}",
|
|
15433
|
-
diffGeneratingMessage: "
|
|
16328
|
+
diffGeneratingMessage: "正在生成建议的 commit message,只会填进你没写的字段。",
|
|
15434
16329
|
diffActionFailed: "仓库操作失败。",
|
|
15435
16330
|
diffIncludeUnstaged: "包含 unstaged 和 untracked 改动",
|
|
15436
16331
|
diffCommitMessage: "Commit message",
|
|
@@ -15448,8 +16343,8 @@ window.__ModuleLoader__.load({
|
|
|
15448
16343
|
diffSubmitting: "执行中…",
|
|
15449
16344
|
diffDone: "完成",
|
|
15450
16345
|
diffCommitCompleted: "已创建 commit {commit}",
|
|
16346
|
+
diffPrCompleted: "已创建 PR,可在仓库栏打开",
|
|
15451
16347
|
diffCommitPreserved: "本地 commit {commit} 已保留。",
|
|
15452
|
-
diffOpenPr: "打开 Pull Request",
|
|
15453
16348
|
diffMergePr: "Merge",
|
|
15454
16349
|
repositoryMergeMenu: "打开 PR 合并选项",
|
|
15455
16350
|
diffMerge_merge: "合并提交 (merge)",
|
|
@@ -15544,6 +16439,20 @@ window.__ModuleLoader__.load({
|
|
|
15544
16439
|
reviewCommentSubmit: "注释",
|
|
15545
16440
|
reviewCommentCancel: "取消",
|
|
15546
16441
|
reviewCommentRemove: "删除评论",
|
|
16442
|
+
reviewThreadReply: "回复",
|
|
16443
|
+
reviewThreadBot: "Bot",
|
|
16444
|
+
reviewThreadAgo: "{age}前",
|
|
16445
|
+
reviewThreadReplyTo: "回复 @{author}",
|
|
16446
|
+
reviewThreadOpenOnGitHub: "在 GitHub 上打开",
|
|
16447
|
+
reviewThreadSend: "发送回复",
|
|
16448
|
+
reviewThreadResolve: "标记为已解决",
|
|
16449
|
+
reviewThreadUnresolve: "重新打开",
|
|
16450
|
+
reviewThreadResolved: "已解决",
|
|
16451
|
+
reviewThreadOutdated: "已过时",
|
|
16452
|
+
reviewThreadReplyPlaceholder: "回复这条评论,输入 @ 可提及成员",
|
|
16453
|
+
reviewThreadMention: "提及仓库成员",
|
|
16454
|
+
reviewThreadReplyFailed: "回复没有发送成功。",
|
|
16455
|
+
reviewThreadResolveFailed: "线程状态没有更新成功。",
|
|
15547
16456
|
reviewCommentFailed: "评论操作失败。",
|
|
15548
16457
|
reviewCommentsClear: "清除全部评论",
|
|
15549
16458
|
reviewCommentsSend: "发送评论",
|
|
@@ -15585,6 +16494,9 @@ window.__ModuleLoader__.load({
|
|
|
15585
16494
|
toolInput: "Input",
|
|
15586
16495
|
toolOutput: "Output",
|
|
15587
16496
|
toolError: "Error",
|
|
16497
|
+
markdownCopy: "Copy",
|
|
16498
|
+
markdownCopied: "Copied",
|
|
16499
|
+
markdownFootnotes: "Footnotes",
|
|
15588
16500
|
tokens: "{count} tokens",
|
|
15589
16501
|
doctor: "Run Doctor",
|
|
15590
16502
|
refreshing: "Running Doctor…",
|
|
@@ -15757,6 +16669,12 @@ window.__ModuleLoader__.load({
|
|
|
15757
16669
|
diffTruncated: "The diff exceeds the safe display limit. Use the terminal to inspect the complete content.",
|
|
15758
16670
|
diffEmpty: "No tracked file changes to display",
|
|
15759
16671
|
diffMaximize: "Maximize diff panel",
|
|
16672
|
+
diffCommentPrevious: "Previous comment",
|
|
16673
|
+
diffCommentNext: "Next comment",
|
|
16674
|
+
diffCommentPosition: "Comment {index} of {total}",
|
|
16675
|
+
diffCommentCounter: "{index}/{total}",
|
|
16676
|
+
diffExpandAll: "Expand all files",
|
|
16677
|
+
diffCollapseAll: "Collapse all files",
|
|
15760
16678
|
diffRestore: "Restore diff panel",
|
|
15761
16679
|
diffCommit: "Commit",
|
|
15762
16680
|
diffCommitMenu: "Open commit actions",
|
|
@@ -15767,7 +16685,7 @@ window.__ModuleLoader__.load({
|
|
|
15767
16685
|
diffPushDescription: "Push local commits to the remote branch.",
|
|
15768
16686
|
diffPushAhead: "{count} unpushed commit(s)",
|
|
15769
16687
|
diffPushCompleted: "Pushed commit {commit}",
|
|
15770
|
-
diffGeneratingMessage: "
|
|
16688
|
+
diffGeneratingMessage: "Suggesting a commit message. It only fills the fields you leave empty.",
|
|
15771
16689
|
diffActionFailed: "Repository action failed.",
|
|
15772
16690
|
diffIncludeUnstaged: "Include unstaged and untracked changes",
|
|
15773
16691
|
diffCommitMessage: "Commit message",
|
|
@@ -15785,8 +16703,8 @@ window.__ModuleLoader__.load({
|
|
|
15785
16703
|
diffSubmitting: "Working…",
|
|
15786
16704
|
diffDone: "Done",
|
|
15787
16705
|
diffCommitCompleted: "Created commit {commit}",
|
|
16706
|
+
diffPrCompleted: "Created the pull request — open it from the repository bar.",
|
|
15788
16707
|
diffCommitPreserved: "Local commit {commit} was preserved.",
|
|
15789
|
-
diffOpenPr: "Open pull request",
|
|
15790
16708
|
diffMergePr: "Merge",
|
|
15791
16709
|
repositoryMergeMenu: "Open merge options",
|
|
15792
16710
|
diffMerge_merge: "Create a merge commit",
|
|
@@ -15881,6 +16799,20 @@ window.__ModuleLoader__.load({
|
|
|
15881
16799
|
reviewCommentSubmit: "Comment",
|
|
15882
16800
|
reviewCommentCancel: "Cancel",
|
|
15883
16801
|
reviewCommentRemove: "Remove comment",
|
|
16802
|
+
reviewThreadReply: "Reply",
|
|
16803
|
+
reviewThreadBot: "Bot",
|
|
16804
|
+
reviewThreadAgo: "{age} ago",
|
|
16805
|
+
reviewThreadReplyTo: "Reply to @{author}",
|
|
16806
|
+
reviewThreadOpenOnGitHub: "Open on GitHub",
|
|
16807
|
+
reviewThreadSend: "Send reply",
|
|
16808
|
+
reviewThreadResolve: "Resolve",
|
|
16809
|
+
reviewThreadUnresolve: "Unresolve",
|
|
16810
|
+
reviewThreadResolved: "Resolved",
|
|
16811
|
+
reviewThreadOutdated: "Outdated",
|
|
16812
|
+
reviewThreadReplyPlaceholder: "Reply to this comment; type @ to mention someone",
|
|
16813
|
+
reviewThreadMention: "Mention a repository member",
|
|
16814
|
+
reviewThreadReplyFailed: "The reply could not be posted.",
|
|
16815
|
+
reviewThreadResolveFailed: "The thread could not be updated.",
|
|
15884
16816
|
reviewCommentFailed: "The comment could not be saved.",
|
|
15885
16817
|
reviewCommentsClear: "Clear all comments",
|
|
15886
16818
|
reviewCommentsSend: "Send comments",
|
|
@@ -15926,8 +16858,11 @@ window.__ModuleLoader__.load({
|
|
|
15926
16858
|
const inject = [
|
|
15927
16859
|
"slots",
|
|
15928
16860
|
"locale",
|
|
15929
|
-
"
|
|
16861
|
+
"remote",
|
|
16862
|
+
"remote.agentPresets",
|
|
15930
16863
|
"sessions",
|
|
16864
|
+
"uiSession",
|
|
16865
|
+
"uiConversation",
|
|
15931
16866
|
"workspaces",
|
|
15932
16867
|
"inputTriggers",
|
|
15933
16868
|
"conversation",
|
|
@@ -15935,6 +16870,14 @@ window.__ModuleLoader__.load({
|
|
|
15935
16870
|
];
|
|
15936
16871
|
function apply(ctx) {
|
|
15937
16872
|
const namespace = "settings.claude-code";
|
|
16873
|
+
const diagnostics = createClaudeDiagnosticsReporter();
|
|
16874
|
+
for (const finding of claudeBootCheckFindings({
|
|
16875
|
+
services: inject,
|
|
16876
|
+
resolve: (name) => ctx.get(name)
|
|
16877
|
+
})) diagnostics.report("boot-check", finding);
|
|
16878
|
+
ctx.effect(() => watchClaudeComposerBar((finding) => {
|
|
16879
|
+
diagnostics.report("boot-check", finding);
|
|
16880
|
+
}), "dsh-claude: composer style drift probe");
|
|
15938
16881
|
ctx.effect(() => ctx.locale.register(namespace, {
|
|
15939
16882
|
zh,
|
|
15940
16883
|
en
|
|
@@ -15947,6 +16890,7 @@ window.__ModuleLoader__.load({
|
|
|
15947
16890
|
const workspaces = ctx.get("workspaces");
|
|
15948
16891
|
const conversation = ctx.get("conversation");
|
|
15949
16892
|
const connection = ctx.get("connection");
|
|
16893
|
+
const remote = ctx.get("remote");
|
|
15950
16894
|
/** Composer submit hook shared by the repository feedback affordances.
|
|
15951
16895
|
* 'append' keeps any user draft and adds the prompt below it; 'idle'
|
|
15952
16896
|
* submits only when the composer is empty and reports false otherwise. */
|
|
@@ -15964,14 +16908,18 @@ window.__ModuleLoader__.load({
|
|
|
15964
16908
|
return true;
|
|
15965
16909
|
};
|
|
15966
16910
|
};
|
|
15967
|
-
|
|
16911
|
+
const uiSession = ctx.get("uiSession");
|
|
16912
|
+
if (uiSession !== void 0) ctx.effect(() => uiSession.provide({
|
|
15968
16913
|
hooks: ["claudeProjection"],
|
|
15969
16914
|
resolve: (binding) => ({ hooks: { claudeProjection: projections.source(binding.sessionId) } })
|
|
15970
16915
|
}), "dsh-claude: sidecar projection provider");
|
|
15971
16916
|
ctx.effect(() => () => projections.dispose(), "dsh-claude: sidecar projection lifecycle");
|
|
15972
|
-
|
|
15973
|
-
|
|
15974
|
-
|
|
16917
|
+
const uiConversation = ctx.get("uiConversation");
|
|
16918
|
+
if (uiConversation !== void 0) {
|
|
16919
|
+
ctx.effect(() => uiConversation.events.register(claudeTurnDefinition), "dsh-claude: Claude turn marker");
|
|
16920
|
+
ctx.effect(() => uiConversation.events.register(claudeActivityStepDefinition), "dsh-claude: Claude activity flow node");
|
|
16921
|
+
ctx.effect(() => uiConversation.events.register(claudeActiveTasksDefinition), "dsh-claude: active Claude tasks node");
|
|
16922
|
+
}
|
|
15975
16923
|
ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
|
|
15976
16924
|
name: "conversation.chat.node",
|
|
15977
16925
|
key: "claude-activity-step",
|
|
@@ -16002,9 +16950,13 @@ window.__ModuleLoader__.load({
|
|
|
16002
16950
|
diffOpen.close();
|
|
16003
16951
|
layout?.closeDetails();
|
|
16004
16952
|
};
|
|
16005
|
-
ctx.effect(() => ctx.slots.onEntryError((key, entry) => {
|
|
16953
|
+
ctx.effect(() => ctx.slots.onEntryError((key, entry, error) => {
|
|
16954
|
+
const id = entry.options.id === void 0 ? "" : ` id="${String(entry.options.id)}"`;
|
|
16955
|
+
const message = error instanceof Error ? `${error.message}
|
|
16956
|
+
${error.stack ?? ""}` : String(error);
|
|
16957
|
+
diagnostics.report("slot-entry-crashed", `slot "${key}"${id}: ${message}`);
|
|
16006
16958
|
if (key === "shell.overlay" && entry.options.id === "claude-diff-overlay") restoreDiff();
|
|
16007
|
-
}), "dsh-claude:
|
|
16959
|
+
}), "dsh-claude: Slot entry failure reporting");
|
|
16008
16960
|
const openTasksPanel = (sessionId, turn) => {
|
|
16009
16961
|
closePluginDetails();
|
|
16010
16962
|
try {
|
|
@@ -16141,8 +17093,8 @@ window.__ModuleLoader__.load({
|
|
|
16141
17093
|
openTasks: (turn) => openTasksPanel(sessionId, turn)
|
|
16142
17094
|
})
|
|
16143
17095
|
}, ClaudeActivityTail));
|
|
16144
|
-
if (
|
|
16145
|
-
const roster = new AgentPresetRoster(
|
|
17096
|
+
if (remote !== void 0) {
|
|
17097
|
+
const roster = new AgentPresetRoster(remote.agentPresets);
|
|
16146
17098
|
const hostT = ctx.locale.bind("settings.agentPreset");
|
|
16147
17099
|
ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
|
|
16148
17100
|
name: "conversation.session.header.actions",
|
|
@@ -16236,12 +17188,59 @@ window.__ModuleLoader__.load({
|
|
|
16236
17188
|
input.setDraft(current.trim() === "" ? text : `${current}\n\n${text}`);
|
|
16237
17189
|
} }
|
|
16238
17190
|
})));
|
|
17191
|
+
/** Compose the chat view the rewind control reads.
|
|
17192
|
+
*
|
|
17193
|
+
* Desktop 2.0 split what used to be one Session snapshot: the Controller's
|
|
17194
|
+
* `binding.session` kept `running`, while the assembled Chat nodes moved to
|
|
17195
|
+
* the Conversation binding's 'chat' target. Reading the old combined shape
|
|
17196
|
+
* threw on `snapshot.chat.order` and took the whole overlay entry down. */
|
|
17197
|
+
const chatSourceCache = /* @__PURE__ */ new Map();
|
|
17198
|
+
const claudeChatSource = (sessionId) => {
|
|
17199
|
+
const cached = chatSourceCache.get(sessionId);
|
|
17200
|
+
if (cached !== void 0) return cached;
|
|
17201
|
+
if (sessions === void 0 || uiConversation === void 0) return void 0;
|
|
17202
|
+
const session = sessions.binding(sessionId)?.session;
|
|
17203
|
+
if (session === void 0) return void 0;
|
|
17204
|
+
let chatTarget;
|
|
17205
|
+
try {
|
|
17206
|
+
chatTarget = uiConversation.binding(sessionId).target("chat");
|
|
17207
|
+
} catch {
|
|
17208
|
+
return;
|
|
17209
|
+
}
|
|
17210
|
+
let lastChat;
|
|
17211
|
+
let lastRunning;
|
|
17212
|
+
let view = EMPTY_CHAT_VIEW;
|
|
17213
|
+
const source = {
|
|
17214
|
+
subscribe(listener) {
|
|
17215
|
+
const dropChat = chatTarget.subscribe(listener);
|
|
17216
|
+
const dropSession = session.subscribe(listener);
|
|
17217
|
+
return () => {
|
|
17218
|
+
dropChat();
|
|
17219
|
+
dropSession();
|
|
17220
|
+
};
|
|
17221
|
+
},
|
|
17222
|
+
getSnapshot() {
|
|
17223
|
+
const chat = chatTarget.getSnapshot();
|
|
17224
|
+
const running = session.getSnapshot().running === true;
|
|
17225
|
+
if (chat === lastChat && running === lastRunning) return view;
|
|
17226
|
+
lastChat = chat;
|
|
17227
|
+
lastRunning = running;
|
|
17228
|
+
view = chat === void 0 ? EMPTY_CHAT_VIEW : {
|
|
17229
|
+
chat,
|
|
17230
|
+
running
|
|
17231
|
+
};
|
|
17232
|
+
return view;
|
|
17233
|
+
}
|
|
17234
|
+
};
|
|
17235
|
+
chatSourceCache.set(sessionId, source);
|
|
17236
|
+
return source;
|
|
17237
|
+
};
|
|
16239
17238
|
if (sessions !== void 0) {
|
|
16240
17239
|
const rewind = {
|
|
16241
17240
|
t,
|
|
16242
17241
|
currentSessionId: () => sessions.list.getSnapshot().current,
|
|
16243
17242
|
subscribeSessions: (listener) => sessions.list.subscribe(listener),
|
|
16244
|
-
chatOf: (sessionId) =>
|
|
17243
|
+
chatOf: (sessionId) => claudeChatSource(sessionId),
|
|
16245
17244
|
projectionOf: (sessionId) => projections.source(sessionId),
|
|
16246
17245
|
...conversation === void 0 ? {} : { setDraft: (sessionId, text) => {
|
|
16247
17246
|
const scope = sessions.scope(sessionId);
|
|
@@ -16273,7 +17272,7 @@ window.__ModuleLoader__.load({
|
|
|
16273
17272
|
};
|
|
16274
17273
|
}
|
|
16275
17274
|
}, ClaudeQueueDock));
|
|
16276
|
-
if (sessions !== void 0 && workspaces !== void 0 && conversation !== void 0 && connection !== void 0) {
|
|
17275
|
+
if (sessions !== void 0 && workspaces !== void 0 && conversation !== void 0 && connection !== void 0 && remote !== void 0) {
|
|
16277
17276
|
/** Attach a prepared worktree to its session without blocking the flow. */
|
|
16278
17277
|
const bindLease = (leaseId, targetSessionId) => {
|
|
16279
17278
|
if (leaseId === void 0) return;
|
|
@@ -16310,12 +17309,9 @@ window.__ModuleLoader__.load({
|
|
|
16310
17309
|
const targetSessionId = await workspaces.connectWorkspace(workspace.workspaceId);
|
|
16311
17310
|
const targetScope = sessions.scope(targetSessionId);
|
|
16312
17311
|
if (targetScope === void 0) throw new Error(t("repositorySessionUnavailable"));
|
|
16313
|
-
const presetResponse = await
|
|
16314
|
-
|
|
16315
|
-
|
|
16316
|
-
});
|
|
16317
|
-
if (!presetResponse.result.ok) throw new Error(presetResponse.result.error.message);
|
|
16318
|
-
sessions.noteAgentPreset(targetSessionId, presetResponse.result.value.agentPreset);
|
|
17312
|
+
const presetResponse = await remote.agentPresets.select(targetSessionId, "claude");
|
|
17313
|
+
if (!presetResponse.ok) throw new Error(presetResponse.error.message);
|
|
17314
|
+
sessions.noteAgentPreset(targetSessionId, presetResponse.value);
|
|
16319
17315
|
const targetInput = conversation.input.for(targetScope);
|
|
16320
17316
|
onProgress("transferring-draft");
|
|
16321
17317
|
if (imageIds.length > 0 && !targetInput.addImages(imageIds)) throw new Error(t("repositoryDraftTransferFailed"));
|
|
@@ -16354,12 +17350,9 @@ window.__ModuleLoader__.load({
|
|
|
16354
17350
|
const targetSessionId = await workspaces.connectWorkspace(workspace.workspaceId);
|
|
16355
17351
|
const targetScope = sessions.scope(targetSessionId);
|
|
16356
17352
|
if (targetScope === void 0) throw new Error(t("repositorySessionUnavailable"));
|
|
16357
|
-
const presetResponse = await
|
|
16358
|
-
|
|
16359
|
-
|
|
16360
|
-
});
|
|
16361
|
-
if (!presetResponse.result.ok) throw new Error(presetResponse.result.error.message);
|
|
16362
|
-
sessions.noteAgentPreset(targetSessionId, presetResponse.result.value.agentPreset);
|
|
17353
|
+
const presetResponse = await remote.agentPresets.select(targetSessionId, "claude");
|
|
17354
|
+
if (!presetResponse.ok) throw new Error(presetResponse.error.message);
|
|
17355
|
+
sessions.noteAgentPreset(targetSessionId, presetResponse.value);
|
|
16363
17356
|
const targetInput = conversation.input.for(targetScope);
|
|
16364
17357
|
report("transferring-draft");
|
|
16365
17358
|
targetInput.setDraft(rawDraft.trim() === "" ? ticketPrompt(ticket) : `${rawDraft.trimEnd()}\n\n${ticketContext(ticket)}`);
|