dsh-ui-tweaks 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -32,6 +32,20 @@ const react_dom_1 = require("react-dom");
32
32
  const GIT_ROUTE = '/_dsh/ui-tweaks/git';
33
33
  /** Poll interval for the status snapshot, in ms. */
34
34
  const POLL_MS = 10000;
35
+ /** Default cap of the file list while its height is still automatic, in px. */
36
+ const FILES_AUTO_MAX = 150;
37
+ /** Default cap of the commit dialog's file list, in px. */
38
+ const MODAL_FILES_AUTO_MAX = 132;
39
+ /** Floors for the three resizable diff-panel sections, in px. */
40
+ const MIN_FILES_H = 30;
41
+ const MIN_DIFF_H = 60;
42
+ const MIN_COMMIT_H = 62;
43
+ /** Share of the panel a dragged section may never exceed, so the diff survives. */
44
+ const SECTION_MAX = '45%';
45
+ const NOOP_STORE = {
46
+ getSnapshot: () => undefined,
47
+ subscribe: () => () => { },
48
+ };
35
49
  async function apiGet(path) {
36
50
  const response = await fetch(path, { credentials: 'same-origin' });
37
51
  const body = await response.json();
@@ -58,260 +72,331 @@ async function apiPost(path, payload) {
58
72
  // ---------------------------------------------------------------------------
59
73
  // GitBar styles — DSH theme tokens only (light + dark).
60
74
  // ---------------------------------------------------------------------------
61
- exports.GITBAR_CSS = `
62
- /* DSH does not force border-box globally; normalize it for the whole GitBar
63
- subtree (including the body-portaled panels/modal), or widths overflow. */
64
- .gbar,.gbar *,.gbar-side,.gbar-side *,.gbar-modal-wrap,.gbar-modal-wrap *,.gbar-notice,.gbar-notice *{box-sizing:border-box}
65
- .gbar{
66
- display:flex;align-items:center;gap:6px;flex-wrap:wrap;position:relative;justify-content:space-between;padding:0 6px 0 0;
67
- /* Align the pill row inside the composer's tool row: the branch pill's left
68
- sits near the "+" button's right edge and the commit pill's right near the
69
- send button's left edge. The composer card is inset 16px from the column
70
- and its tool row adds the button widths — about 60px of inset per side
71
- here. buildRuntimeCss overrides the cap (!important) when the dialog
72
- width changes. */
73
- width:calc(100% - 120px);max-width:706px;margin-inline:auto;
74
- /* Solid background: messages scroll behind the sticky composer seat, and a
75
- transparent row would let text show through the pills. */
76
- background:var(--dsw-alias-bg-layer-1);
77
- }
78
- .gbar-right{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}
79
- .gbar-pill{
80
- display:inline-flex;align-items:center;gap:6px;
81
- height:26px;padding:0 10px;
82
- background:var(--dsw-alias-bg-module-platform);
83
- border:1px solid var(--dsw-alias-border-l2);
84
- border-radius:8px;
85
- color:var(--dsw-alias-label-primary);
86
- font:inherit;font-size:12.5px;line-height:1;
87
- cursor:pointer;
88
- transition:background .15s ease,border-color .15s ease;
89
- white-space:nowrap;
90
- -webkit-user-select:none;user-select:none;
91
- }
92
- .gbar-pill:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}
93
- .gbar-pill .gbar-ico{width:13px;height:13px;flex:none;opacity:.85}
94
- .gbar-pill .gbar-caret{font-size:8px;color:var(--dsw-alias-label-tertiary);margin-left:1px}
95
- .gbar-pill .gbar-dot{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-state-warn-primary);flex:none}
96
- .gbar-pill .gbar-add{color:var(--dsw-alias-state-success-primary);font-weight:600;font-variant-numeric:tabular-nums}
97
- .gbar-pill .gbar-del{color:var(--dsw-alias-state-error-primary);font-weight:600;font-variant-numeric:tabular-nums}
98
- .gbar-pill .gbar-meta{color:var(--dsw-alias-label-secondary)}
99
- .gbar-pill .gbar-hint{color:var(--dsw-alias-label-tertiary);font-weight:400}
100
- .gbar-pill.gbar-active{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-business-primary)}
101
- .gbar-pill.gbar-active .gbar-hint{color:var(--dsw-alias-state-business-primary)}
102
- .gbar-pill:disabled{opacity:.5;cursor:default}
103
-
104
- /* branch popup — opens upward so the composer below stays uncovered */
105
- .gbar-pop{
106
- position:absolute;left:0;bottom:calc(100% + 6px);z-index:90;
107
- width:286px;max-height:min(360px,calc(100vh - 140px));overflow:hidden auto;
108
- background:var(--dsw-alias-bg-layer-1);
109
- border:1px solid var(--dsw-alias-border-l2);border-radius:14px;
110
- box-shadow:var(--dsw-shadow-lv2);
111
- padding:6px;display:flex;flex-direction:column;gap:1px;
112
- }
113
- .gbar-pop .gbar-sec{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);padding:7px 9px 3px}
114
- .gbar-pop .gbar-row{
115
- display:flex;align-items:center;gap:8px;width:100%;
116
- padding:7px 9px;border:none;border-radius:8px;
117
- background:transparent;color:var(--dsw-alias-label-primary);
118
- font:inherit;font-size:13px;cursor:pointer;text-align:left;
119
- }
120
- .gbar-pop .gbar-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
121
- .gbar-pop .gbar-row.gbar-cur{color:var(--dsw-alias-state-business-primary);font-weight:600}
122
- .gbar-pop .gbar-row .gbar-check{margin-left:auto;color:var(--dsw-alias-state-business-primary);font-weight:700}
123
- .gbar-pop .gbar-row .gbar-rm{font-size:10.5px;color:var(--dsw-alias-label-tertiary);flex:none}
124
- /* branch row wrapper: main switch button + delete button */
125
- .gbar-pop .gbar-rowwrap{display:flex;align-items:center;gap:2px;border-radius:8px}
126
- .gbar-pop .gbar-rowwrap:hover{background:var(--dsw-alias-interactive-bg-hover)}
127
- .gbar-pop .gbar-rowwrap .gbar-row{background:transparent}
128
- .gbar-pop .gbar-del{
129
- flex:none;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);
130
- font:inherit;font-size:12px;cursor:pointer;padding:6px 8px;border-radius:6px;margin-right:3px;
131
- }
132
- .gbar-pop .gbar-del:hover{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
133
- .gbar-pop .gbar-del.gbar-arm{color:var(--dsw-alias-state-error-primary);font-weight:600}
134
- .gbar-pushrow{display:flex;align-items:center;gap:7px;padding:0 8px 7px}
135
- .gbar-pushrow .gbar-pushlabel{font-size:12px;color:var(--dsw-alias-label-secondary)}
136
- .gbar-pop .gbar-newrow{display:flex;gap:6px;padding:8px 6px 6px}
137
- .gbar-pop input{
138
- flex:1;min-width:0;height:32px;padding:0 11px;
139
- border:1px solid var(--dsw-alias-border-l2);border-radius:9px;
140
- background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);
141
- font:inherit;font-size:13px;outline:none;
142
- }
143
- .gbar-pop input:focus{border-color:var(--dsw-alias-state-business-primary)}
144
- .gbar-pop input::placeholder{color:var(--dsw-alias-label-tertiary)}
145
- .gbar-mini{
146
- flex:none;height:32px;padding:0 14px;border:none;border-radius:9px;
147
- background:var(--dsw-alias-state-business-primary);color:#fff;
148
- font:inherit;font-size:13px;font-weight:500;cursor:pointer;
149
- }
150
- .gbar-mini:hover{opacity:.92}
151
- .gbar-mini:disabled{opacity:.5;cursor:default}
152
-
153
- /* diff side panel — fixed on the right; the conversation is pushed left via
154
- #root { margin-right } so the timeline rail stays visible. */
155
- .gbar-side{
156
- position:fixed;right:0;top:0;bottom:0;z-index:80;
157
- display:flex;flex-direction:column;
158
- background:var(--dsw-alias-bg-layer-1);
159
- border-left:1px solid var(--dsw-alias-border-l2);
160
- box-shadow:var(--dsw-shadow-lv2);
161
- animation:gbar-in .18s cubic-bezier(.32,.72,0,1);
162
- }
163
- /* drag handle on the panel's left edge */
164
- .gbar-resize{
165
- position:absolute;left:-5px;top:0;bottom:0;width:10px;cursor:col-resize;
166
- touch-action:none;
167
- }
168
- .gbar-resize::after{
169
- content:"";position:absolute;left:4px;top:0;bottom:0;width:2px;
170
- background:transparent;transition:background .15s ease;
171
- }
172
- .gbar-side:hover .gbar-resize::after{background:var(--dsw-alias-border-l2)}
173
- .gbar-resize:active::after{background:var(--dsw-alias-state-business-primary)}
174
- @keyframes gbar-in{from{opacity:0;transform:translateX(14px)}to{opacity:1;transform:none}}
175
- .gbar-side-head{display:flex;align-items:center;gap:10px;padding:12px 14px;border-bottom:1px solid var(--dsw-alias-border-l1)}
176
- .gbar-side-head .gbar-title{font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
177
- .gbar-side-head .gbar-sub{font-size:12px;color:var(--dsw-alias-label-tertiary);flex:none}
178
- .gbar-side-head .gbar-spacer{flex:1}
179
- .gbar-seg{display:inline-flex;padding:3px;gap:2px;border-radius:10px;background:var(--dsw-alias-bg-module-platform);flex:none}
180
- .gbar-seg button{border:none;border-radius:8px;padding:4px 10px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer}
181
- .gbar-seg button.gbar-on{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv1)}
182
- .gbar-side-x{border:none;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:15px;cursor:pointer;width:28px;height:28px;border-radius:8px;flex:none}
183
- .gbar-side-x:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
184
- .gbar-side-body{flex:1;overflow:hidden;display:flex;flex-direction:column;min-height:0}
185
- .gbar-files{overflow-y:auto;border-bottom:1px solid var(--dsw-alias-border-l1);max-height:150px}
186
- .gbar-file{
187
- display:flex;align-items:center;gap:6px;width:100%;
188
- padding:3px 14px;background:transparent;
189
- }
190
- .gbar-file .gbar-file-main{
191
- flex:1;min-width:0;display:flex;align-items:center;gap:9px;
192
- padding:5px 4px;border:none;border-radius:7px;background:transparent;
193
- color:var(--dsw-alias-label-primary);font:inherit;font-size:12.5px;cursor:pointer;text-align:left;
194
- }
195
- .gbar-file .gbar-file-main:hover{background:var(--dsw-alias-interactive-bg-hover)}
196
- .gbar-file.gbar-on .gbar-file-main{background:var(--dsw-alias-interactive-bg-hover)}
197
- .gbar-file.gbar-excl{opacity:.55}
198
- .gbar-chk{
199
- flex:none;width:16px;height:16px;padding:0;
200
- border:1px solid var(--dsw-alias-border-l2);border-radius:5px;
201
- background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-state-business-primary);
202
- font-size:11px;line-height:1;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;
203
- }
204
- .gbar-chk:hover{border-color:var(--dsw-alias-state-business-primary)}
205
- .gbar-chk.gbar-off{color:transparent}
206
- .gbar-file .gbar-st{flex:none;width:16px;font-weight:700;font-size:12px}
207
- .gbar-file .gbar-st.gbar-m{color:var(--dsw-alias-state-warn-primary)}
208
- .gbar-file .gbar-st.gbar-a{color:var(--dsw-alias-state-success-primary)}
209
- .gbar-file .gbar-st.gbar-d{color:var(--dsw-alias-state-error-primary)}
210
- .gbar-file .gbar-st.gbar-u{color:var(--dsw-alias-label-tertiary)}
211
- .gbar-file .gbar-path{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:12px}
212
- .gbar-file .gbar-nums{flex:none;font-variant-numeric:tabular-nums;font-size:11.5px}
213
- .gbar-file .gbar-nums .gbar-a{color:var(--dsw-alias-state-success-primary)}
214
- .gbar-file .gbar-nums .gbar-d{color:var(--dsw-alias-state-error-primary)}
215
- .gbar-diff{flex:1;overflow:auto;font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:12px;line-height:1.7;padding:8px 0}
216
- .gbar-diff .gbar-hunk{display:flex;align-items:center;height:24px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-markdown-inline-code);padding:0 14px;font-size:11.5px;white-space:nowrap}
217
- .gbar-diff .gbar-line{display:flex;align-items:center;min-height:21px;padding:0 14px 0 0;white-space:pre}
218
- .gbar-diff .gbar-line .gbar-ln{flex:none;width:46px;text-align:right;padding-right:12px;color:var(--dsw-alias-label-tertiary);font-size:11px;-webkit-user-select:none;user-select:none}
219
- .gbar-diff .gbar-line .gbar-code{flex:1;white-space:pre;color:var(--dsw-alias-label-primary)}
220
- .gbar-diff .gbar-line.gbar-add{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 14%,transparent)}
221
- .gbar-diff .gbar-line.gbar-add .gbar-ln{color:var(--dsw-alias-state-success-primary)}
222
- .gbar-diff .gbar-line.gbar-del{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
223
- .gbar-diff .gbar-line.gbar-del .gbar-ln{color:var(--dsw-alias-state-error-primary)}
224
- .gbar-diff .gbar-line.gbar-ctx .gbar-code{color:var(--dsw-alias-label-secondary)}
225
- .gbar-diff .gbar-empty{padding:18px 16px;font-size:12px;color:var(--dsw-alias-label-tertiary)}
226
- .gbar-side-foot{padding:8px 14px;border-top:1px solid var(--dsw-alias-border-l1);font-size:11.5px;color:var(--dsw-alias-label-tertiary);display:flex;gap:8px;align-items:center}
227
- .gbar-side-foot .gbar-dot{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-state-warn-primary);flex:none}
228
- /* commit row inside the diff panel */
229
- .gbar-side-commit{display:flex;flex-direction:column;gap:7px;padding:9px 12px;border-top:1px solid var(--dsw-alias-border-l1)}
230
- .gbar-side-commit .gbar-crow{display:flex;align-items:center;gap:6px}
231
- .gbar-side-commit input{
232
- flex:1;min-width:0;height:28px;padding:0 10px;
233
- border:1px solid var(--dsw-alias-border-l2);border-radius:8px;
234
- background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);
235
- font:inherit;font-size:12px;outline:none;
236
- }
237
- .gbar-side-commit input:focus{border-color:var(--dsw-alias-state-business-primary)}
238
- .gbar-side-commit input::placeholder{color:var(--dsw-alias-label-tertiary)}
239
- .gbar-side-commit .gbar-actions{display:flex;align-items:center;justify-content:flex-end;gap:6px}
240
- .gbar-side-commit .gbar-btn{height:28px;padding:0 12px;font-size:12px;border-radius:8px}
241
-
242
- /* commit modal */
243
- .gbar-modal-wrap{
244
- position:fixed;inset:0;z-index:120;
245
- display:flex;align-items:center;justify-content:center;
246
- background:rgba(0,0,0,.35);
247
- }
248
- .gbar-modal{
249
- width:min(520px,calc(100vw - 40px));max-height:calc(100vh - 48px);overflow:hidden auto;
250
- background:var(--dsw-alias-bg-layer-1);
251
- border:1px solid var(--dsw-alias-border-l2);border-radius:16px;
252
- box-shadow:var(--dsw-shadow-lv2);
253
- padding:18px;
254
- display:flex;flex-direction:column;gap:12px;
255
- animation:gbar-in .18s cubic-bezier(.32,.72,0,1);
256
- }
257
- .gbar-modal .gbar-head{display:flex;align-items:center;gap:10px}
258
- .gbar-modal .gbar-head .gbar-title{font-size:15px;font-weight:600}
259
- .gbar-modal .gbar-head .gbar-branch{font-size:12px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-module-platform);border-radius:999px;padding:3px 10px}
260
- .gbar-modal .gbar-head .gbar-x{margin-left:auto;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:16px;cursor:pointer;width:28px;height:28px;border-radius:8px}
261
- .gbar-modal .gbar-head .gbar-x:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
262
- .gbar-modal textarea{
263
- width:100%;min-height:64px;height:auto;max-height:220px;resize:none;
264
- overflow-y:auto;scrollbar-width:none;
265
- border:1px solid var(--dsw-alias-border-l2);border-radius:12px;
266
- background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);
267
- font:inherit;font-size:14px;line-height:1.6;padding:10px 14px;outline:none;
268
- }
269
- .gbar-modal textarea::-webkit-scrollbar{display:none}
270
- .gbar-modal textarea:focus{border-color:var(--dsw-alias-state-business-primary)}
271
- .gbar-modal textarea::placeholder{color:var(--dsw-alias-label-tertiary)}
272
- .gbar-modal .gbar-hint{font-size:12px;color:var(--dsw-alias-label-tertiary);line-height:1.6}
273
- .gbar-modal .gbar-files-head{display:flex;align-items:center;gap:8px;font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);margin-top:2px}
274
- .gbar-modal .gbar-files-head .gbar-hint{font-size:11px;font-weight:400;text-transform:none;letter-spacing:0}
275
- .gbar-modal .gbar-files{
276
- display:flex;flex-direction:column;gap:1px;max-height:132px;overflow-y:auto;
277
- border:1px solid var(--dsw-alias-border-l1);border-radius:10px;
278
- background:var(--dsw-alias-bg-layer-2);padding:4px;
279
- }
280
- .gbar-modal .gbar-file{
281
- display:flex;align-items:center;gap:6px;width:100%;
282
- padding:2px 6px;border-radius:7px;background:transparent;
283
- }
284
- .gbar-modal .gbar-file .gbar-file-main{
285
- padding:4px 4px;font-size:12px;border-radius:6px;
286
- }
287
- .gbar-modal .gbar-file .gbar-file-main:hover{background:var(--dsw-alias-interactive-bg-hover)}
288
- .gbar-modal .gbar-file.gbar-on .gbar-file-main{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 10%,transparent)}
289
- .gbar-modal .gbar-file .gbar-path{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:11.5px}
290
- .gbar-modal .gbar-file .gbar-goto{flex:none;color:var(--dsw-alias-label-tertiary);font-size:10px}
291
- .gbar-modal .gbar-file.gbar-on .gbar-goto{color:var(--dsw-alias-state-business-primary)}
292
- .gbar-modal .gbar-foot{display:flex;align-items:center;justify-content:flex-end;gap:8px;margin-top:2px;flex-wrap:wrap}
293
- .gbar-btn{
294
- height:34px;padding:0 16px;border:none;border-radius:10px;
295
- font:inherit;font-size:13.5px;cursor:pointer;
296
- display:inline-flex;align-items:center;gap:6px;
297
- }
298
- .gbar-btn.gbar-ghost{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}
299
- .gbar-btn.gbar-ghost:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}
300
- .gbar-btn.gbar-soft{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary)}
301
- .gbar-btn.gbar-soft:hover{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 18%,transparent)}
302
- .gbar-btn.gbar-primary{background:var(--dsw-alias-state-business-primary);color:#fff;font-weight:500}
303
- .gbar-btn.gbar-primary:hover{opacity:.92}
304
- .gbar-btn:disabled{opacity:.5;cursor:default}
305
- .gbar-notice{
306
- position:fixed;z-index:150;left:50%;bottom:28px;transform:translateX(-50%);
307
- max-width:min(520px,90vw);padding:9px 16px;border-radius:10px;font-size:12.5px;line-height:1.5;
308
- box-shadow:var(--dsw-shadow-lv2);animation:gbar-in .18s cubic-bezier(.32,.72,0,1);
309
- }
310
- .gbar-notice.gbar-ok{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 16%,var(--dsw-alias-bg-layer-1));color:var(--dsw-alias-state-success-primary)}
311
- .gbar-notice.gbar-err{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 14%,var(--dsw-alias-bg-layer-1));color:var(--dsw-alias-state-error-primary)}
312
- .gbar-spin{width:12px;height:12px;border-radius:50%;border:2px solid color-mix(in srgb,var(--dsw-alias-label-tertiary) 30%,transparent);border-top-color:currentColor;animation:gbar-spin .7s linear infinite}
313
- @keyframes gbar-spin{to{transform:rotate(360deg)}}
314
- @media (prefers-reduced-motion:reduce){.gbar-side,.gbar-modal,.gbar-notice{animation:none}}
75
+ exports.GITBAR_CSS = `
76
+ /* DSH does not force border-box globally; normalize it for the whole GitBar
77
+ subtree (including the body-portaled panels/modal), or widths overflow. */
78
+ .gbar,.gbar *,.gbar-side,.gbar-side *,.gbar-modal-wrap,.gbar-modal-wrap *,.gbar-notice,.gbar-notice *{box-sizing:border-box}
79
+ .gbar{
80
+ display:flex;align-items:center;gap:6px;flex-wrap:wrap;position:relative;justify-content:space-between;padding:0 6px 0 0;
81
+ /* Align the pill row inside the composer's tool row: the branch pill's left
82
+ sits near the "+" button's right edge and the commit pill's right near the
83
+ send button's left edge. The composer card is inset 16px from the column
84
+ and its tool row adds the button widths — about 60px of inset per side
85
+ here. buildRuntimeCss overrides the cap (!important) when the dialog
86
+ width changes. */
87
+ width:calc(100% - 120px);max-width:706px;margin-inline:auto;
88
+ /* The row itself paints nothing: only the pills are visible, so the composer
89
+ seat below shows through instead of a floating opaque strip. The pills are
90
+ transparent at rest too and only fill in on hover / while open. */
91
+ background:transparent;
92
+ }
93
+ .gbar-right{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap}
94
+ .gbar-pill{
95
+ display:inline-flex;align-items:center;gap:6px;
96
+ height:26px;padding:0 10px;
97
+ background:transparent;
98
+ border:none;
99
+ border-radius:8px;
100
+ color:var(--dsw-alias-label-primary);
101
+ font:inherit;font-size:12.5px;line-height:1;
102
+ cursor:pointer;
103
+ transition:background .15s ease;
104
+ white-space:nowrap;
105
+ -webkit-user-select:none;user-select:none;
106
+ }
107
+ .gbar-pill:hover{background:var(--dsw-alias-bg-module-platform)}
108
+ .gbar-pill:focus-visible{background:var(--dsw-alias-bg-module-platform)}
109
+ .gbar-pill .gbar-ico{width:13px;height:13px;flex:none;opacity:.85}
110
+ .gbar-pill .gbar-caret{font-size:8px;color:var(--dsw-alias-label-tertiary);margin-left:1px}
111
+ .gbar-pill .gbar-dot{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-state-warn-primary);flex:none}
112
+ .gbar-pill .gbar-add{color:var(--dsw-alias-state-success-primary);font-weight:600;font-variant-numeric:tabular-nums}
113
+ .gbar-pill .gbar-del{color:var(--dsw-alias-state-error-primary);font-weight:600;font-variant-numeric:tabular-nums}
114
+ .gbar-pill .gbar-meta{color:var(--dsw-alias-label-secondary)}
115
+ .gbar-pill .gbar-hint{color:var(--dsw-alias-label-tertiary);font-weight:400}
116
+ .gbar-pill.gbar-active{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-business-primary)}
117
+ .gbar-pill.gbar-active .gbar-hint{color:var(--dsw-alias-state-business-primary)}
118
+ .gbar-pill:disabled{opacity:.5;cursor:default}
119
+
120
+ /* branch popup — opens upward so the composer below stays uncovered */
121
+ .gbar-pop{
122
+ position:absolute;left:0;bottom:calc(100% + 6px);z-index:90;
123
+ width:286px;max-height:min(360px,calc(100vh - 140px));overflow:hidden auto;
124
+ background:var(--dsw-alias-bg-layer-1);
125
+ border:1px solid var(--dsw-alias-border-l2);border-radius:14px;
126
+ box-shadow:var(--dsw-shadow-lv2);
127
+ padding:6px;display:flex;flex-direction:column;gap:1px;
128
+ }
129
+ .gbar-pop .gbar-sec{font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);padding:7px 9px 3px}
130
+ .gbar-pop .gbar-row{
131
+ display:flex;align-items:center;gap:8px;width:100%;
132
+ padding:7px 9px;border:none;border-radius:8px;
133
+ background:transparent;color:var(--dsw-alias-label-primary);
134
+ font:inherit;font-size:13px;cursor:pointer;text-align:left;
135
+ }
136
+ .gbar-pop .gbar-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
137
+ .gbar-pop .gbar-row.gbar-cur{color:var(--dsw-alias-state-business-primary);font-weight:600}
138
+ .gbar-pop .gbar-row .gbar-check{margin-left:auto;color:var(--dsw-alias-state-business-primary);font-weight:700}
139
+ .gbar-pop .gbar-row .gbar-rm{font-size:10.5px;color:var(--dsw-alias-label-tertiary);flex:none}
140
+ /* branch row wrapper: main switch button + delete button */
141
+ .gbar-pop .gbar-rowwrap{display:flex;align-items:center;gap:2px;border-radius:8px}
142
+ .gbar-pop .gbar-rowwrap:hover{background:var(--dsw-alias-interactive-bg-hover)}
143
+ .gbar-pop .gbar-rowwrap .gbar-row{background:transparent}
144
+ .gbar-pop .gbar-del{
145
+ flex:none;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);
146
+ font:inherit;font-size:12px;cursor:pointer;padding:6px 8px;border-radius:6px;margin-right:3px;
147
+ }
148
+ .gbar-pop .gbar-del:hover{color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
149
+ .gbar-pop .gbar-del.gbar-arm{color:var(--dsw-alias-state-error-primary);font-weight:600}
150
+ .gbar-pushrow{display:flex;align-items:center;gap:7px;padding:0 8px 7px}
151
+ .gbar-pushrow .gbar-pushlabel{font-size:12px;color:var(--dsw-alias-label-secondary)}
152
+ .gbar-pop .gbar-newrow{display:flex;gap:6px;padding:8px 6px 6px}
153
+ .gbar-pop input{
154
+ flex:1;min-width:0;height:32px;padding:0 11px;
155
+ border:1px solid var(--dsw-alias-border-l2);border-radius:9px;
156
+ background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);
157
+ font:inherit;font-size:13px;outline:none;
158
+ }
159
+ .gbar-pop input:focus{border-color:var(--dsw-alias-state-business-primary)}
160
+ .gbar-pop input::placeholder{color:var(--dsw-alias-label-tertiary)}
161
+ .gbar-mini{
162
+ flex:none;height:32px;padding:0 14px;border:none;border-radius:9px;
163
+ background:var(--dsw-alias-state-business-primary);color:#fff;
164
+ font:inherit;font-size:13px;font-weight:500;cursor:pointer;
165
+ }
166
+ .gbar-mini:hover{opacity:.92}
167
+ .gbar-mini:disabled{opacity:.5;cursor:default}
168
+
169
+ /* branch popup action entries (new branch / graph) */
170
+ .gbar-actions{display:flex;gap:6px;padding:8px 6px 4px;border-top:1px solid var(--dsw-alias-border-l1);margin-top:4px}
171
+ .gbar-act{
172
+ flex:1;display:inline-flex;align-items:center;justify-content:center;gap:7px;
173
+ height:34px;border:none;border-radius:10px;
174
+ background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);
175
+ font:inherit;font-size:12.5px;font-weight:500;cursor:pointer;
176
+ }
177
+ .gbar-act:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}
178
+ .gbar-act svg{width:14px;height:14px;opacity:.9;flex:none}
179
+ /* base-branch selector (new-branch dialog) */
180
+ .gbar-baserow{display:flex;align-items:center;gap:7px;padding:0}
181
+ .gbar-baselabel{font-size:12px;color:var(--dsw-alias-label-secondary);flex:none}
182
+ .gbar-base{
183
+ flex:1;min-width:0;height:32px;padding:0 10px;
184
+ border:1px solid var(--dsw-alias-border-l2);border-radius:9px;
185
+ background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);
186
+ font:inherit;font-size:12.5px;outline:none;cursor:pointer;
187
+ }
188
+ .gbar-base:focus{border-color:var(--dsw-alias-state-business-primary)}
189
+ .gbar-modal input{
190
+ width:100%;height:38px;padding:0 13px;
191
+ border:1px solid var(--dsw-alias-border-l2);border-radius:10px;
192
+ background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);
193
+ font:inherit;font-size:13.5px;outline:none;
194
+ }
195
+ .gbar-modal input:focus{border-color:var(--dsw-alias-state-business-primary)}
196
+ .gbar-modal input::placeholder{color:var(--dsw-alias-label-tertiary)}
197
+ .gbar-modal .gbar-pushrow{padding:0}
198
+ .gbar-x:disabled{opacity:.5;cursor:default}
199
+ /* commit-graph dialog */
200
+ .gbar-modal.gbar-graph-modal{width:min(760px,calc(100vw - 40px));gap:10px}
201
+ /* Refresh sits immediately left of close, both pinned to the right edge: the
202
+ refresh takes the auto margin (specificity .gbar-x.gbar-refresh beats the
203
+ .gbar-x override below), close drops it so they stay adjacent. */
204
+ .gbar-modal.gbar-graph-modal .gbar-head .gbar-x.gbar-refresh{margin-left:auto}
205
+ .gbar-modal.gbar-graph-modal .gbar-head .gbar-x{margin-left:0}
206
+ .gbar-modal.gbar-graph-modal .gbar-x svg{width:15px;height:15px;display:block}
207
+ .gbar-graph-empty{padding:28px 12px;text-align:center;font-size:13px;color:var(--dsw-alias-label-tertiary)}
208
+ .gbar-graph-table{display:flex;flex-direction:column;max-height:min(60vh,540px);overflow:auto;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-bg-layer-2)}
209
+ .gbar-graph-row{display:grid;grid-template-columns:62px 1fr 96px 90px;align-items:center;gap:8px;padding:5px 12px;border-bottom:1px solid var(--dsw-alias-border-l1)}
210
+ .gbar-graph-row:last-child{border-bottom:none}
211
+ .gbar-graph-row:hover{background:var(--dsw-alias-interactive-bg-hover)}
212
+ .gbar-graph-head{position:sticky;top:0;background:var(--dsw-alias-bg-module-platform);font-size:10.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);z-index:1}
213
+ .gbar-graph-head:hover{background:var(--dsw-alias-bg-module-platform)}
214
+ .gbar-c-hash code{font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:11px;color:var(--dsw-alias-label-secondary)}
215
+ .gbar-c-subject{min-width:0;display:flex;align-items:center;gap:8px}
216
+ .gbar-subject{font-size:12.5px;color:var(--dsw-alias-label-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
217
+ .gbar-refs{flex:none;font-size:10.5px;color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);border-radius:999px;padding:1px 8px;white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis}
218
+ .gbar-c-author{font-size:12px;color:var(--dsw-alias-label-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
219
+ .gbar-c-date{font-size:11.5px;color:var(--dsw-alias-label-tertiary);text-align:right;white-space:nowrap}
220
+
221
+ /* diff side panel — fixed on the right; the conversation is pushed left via
222
+ #root { margin-right } so the timeline rail stays visible. */
223
+ .gbar-side{
224
+ position:fixed;right:0;top:0;bottom:0;z-index:80;
225
+ display:flex;flex-direction:column;overflow:hidden;
226
+ background:var(--dsw-alias-bg-layer-1);
227
+ border-left:1px solid var(--dsw-alias-border-l2);
228
+ box-shadow:var(--dsw-shadow-lv2);
229
+ animation:gbar-in .18s cubic-bezier(.32,.72,0,1);
230
+ }
231
+ /* drag handle on the panel's left edge */
232
+ .gbar-resize{
233
+ position:absolute;left:-5px;top:0;bottom:0;width:10px;cursor:col-resize;
234
+ touch-action:none;
235
+ }
236
+ .gbar-resize::after{
237
+ content:"";position:absolute;left:4px;top:0;bottom:0;width:2px;
238
+ background:transparent;transition:background .15s ease;
239
+ }
240
+ .gbar-side:hover .gbar-resize::after{background:var(--dsw-alias-border-l2)}
241
+ .gbar-resize:active::after{background:var(--dsw-alias-state-business-primary)}
242
+ @keyframes gbar-in{from{opacity:0;transform:translateX(14px)}to{opacity:1;transform:none}}
243
+ .gbar-side-head{display:flex;align-items:center;gap:10px;padding:12px 14px;border-bottom:1px solid var(--dsw-alias-border-l1)}
244
+ .gbar-side-head .gbar-title{font-size:13.5px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
245
+ .gbar-side-head .gbar-sub{font-size:12px;color:var(--dsw-alias-label-tertiary);flex:none}
246
+ .gbar-side-head .gbar-spacer{flex:1}
247
+ .gbar-seg{display:inline-flex;padding:3px;gap:2px;border-radius:10px;background:var(--dsw-alias-bg-module-platform);flex:none}
248
+ .gbar-seg button{border:none;border-radius:8px;padding:4px 10px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer}
249
+ .gbar-seg button.gbar-on{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv1)}
250
+ .gbar-side-x{border:none;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:15px;cursor:pointer;width:28px;height:28px;border-radius:8px;flex:none}
251
+ .gbar-side-x:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
252
+ .gbar-side-body{flex:1;overflow:hidden;display:flex;flex-direction:column;min-height:0}
253
+ /* The three stacked sections (files / diff / commit) are sized by drag: the two
254
+ neighbours carry an explicit inline height and the diff pane absorbs whatever
255
+ is left, so a drag can never overflow the panel. The dividing hairlines are
256
+ painted by the splitters, not by the sections' own borders. */
257
+ .gbar-files{flex:none;overflow-y:auto}
258
+ /* horizontal drag splitters between the sections */
259
+ .gbar-vsplit{
260
+ flex:none;position:relative;height:7px;
261
+ cursor:row-resize;touch-action:none;-webkit-user-select:none;user-select:none;
262
+ }
263
+ .gbar-vsplit::after{
264
+ content:"";position:absolute;left:0;right:0;top:3px;height:1px;
265
+ background:var(--dsw-alias-border-l1);transition:background .15s ease,height .15s ease;
266
+ }
267
+ .gbar-vsplit:hover::after{background:var(--dsw-alias-border-l2);height:2px}
268
+ .gbar-vsplit.gbar-dragging::after{background:var(--dsw-alias-state-business-primary);height:2px}
269
+ .gbar-file{
270
+ display:flex;align-items:center;gap:6px;width:100%;
271
+ padding:3px 14px;background:transparent;
272
+ }
273
+ .gbar-file .gbar-file-main{
274
+ flex:1;min-width:0;display:flex;align-items:center;gap:9px;
275
+ padding:5px 4px;border:none;border-radius:7px;background:transparent;
276
+ color:var(--dsw-alias-label-primary);font:inherit;font-size:12.5px;cursor:pointer;text-align:left;
277
+ }
278
+ .gbar-file .gbar-file-main:hover{background:var(--dsw-alias-interactive-bg-hover)}
279
+ .gbar-file.gbar-on .gbar-file-main{background:var(--dsw-alias-interactive-bg-hover)}
280
+ .gbar-file.gbar-excl{opacity:.55}
281
+ .gbar-chk{
282
+ flex:none;width:16px;height:16px;padding:0;
283
+ border:1px solid var(--dsw-alias-border-l2);border-radius:5px;
284
+ background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-state-business-primary);
285
+ font-size:11px;line-height:1;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;
286
+ }
287
+ .gbar-chk:hover{border-color:var(--dsw-alias-state-business-primary)}
288
+ .gbar-chk.gbar-off{color:transparent}
289
+ .gbar-file .gbar-st{flex:none;width:16px;font-weight:700;font-size:12px}
290
+ .gbar-file .gbar-st.gbar-m{color:var(--dsw-alias-state-warn-primary)}
291
+ .gbar-file .gbar-st.gbar-a{color:var(--dsw-alias-state-success-primary)}
292
+ .gbar-file .gbar-st.gbar-d{color:var(--dsw-alias-state-error-primary)}
293
+ .gbar-file .gbar-st.gbar-u{color:var(--dsw-alias-label-tertiary)}
294
+ .gbar-file .gbar-path{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:12px}
295
+ .gbar-file .gbar-nums{flex:none;font-variant-numeric:tabular-nums;font-size:11.5px}
296
+ .gbar-file .gbar-nums .gbar-a{color:var(--dsw-alias-state-success-primary)}
297
+ .gbar-file .gbar-nums .gbar-d{color:var(--dsw-alias-state-error-primary)}
298
+ .gbar-diff{flex:1;min-height:0;overflow:auto;font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:12px;line-height:1.7;padding:8px 0}
299
+ .gbar-diff .gbar-hunk{display:flex;align-items:center;height:24px;color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-markdown-inline-code);padding:0 14px;font-size:11.5px;white-space:nowrap}
300
+ .gbar-diff .gbar-line{display:flex;align-items:center;min-height:21px;padding:0 14px 0 0;white-space:pre}
301
+ .gbar-diff .gbar-line .gbar-ln{flex:none;width:46px;text-align:right;padding-right:12px;color:var(--dsw-alias-label-tertiary);font-size:11px;-webkit-user-select:none;user-select:none}
302
+ .gbar-diff .gbar-line .gbar-code{flex:1;white-space:pre;color:var(--dsw-alias-label-primary)}
303
+ .gbar-diff .gbar-line.gbar-add{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 14%,transparent)}
304
+ .gbar-diff .gbar-line.gbar-add .gbar-ln{color:var(--dsw-alias-state-success-primary)}
305
+ .gbar-diff .gbar-line.gbar-del{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent)}
306
+ .gbar-diff .gbar-line.gbar-del .gbar-ln{color:var(--dsw-alias-state-error-primary)}
307
+ .gbar-diff .gbar-line.gbar-ctx .gbar-code{color:var(--dsw-alias-label-secondary)}
308
+ .gbar-diff .gbar-empty{padding:18px 16px;font-size:12px;color:var(--dsw-alias-label-tertiary)}
309
+ /* The hairline above the foot is drawn by the commit splitter that precedes it. */
310
+ .gbar-side-foot{flex:none;padding:8px 14px;font-size:11.5px;color:var(--dsw-alias-label-tertiary);display:flex;gap:8px;align-items:center}
311
+ .gbar-side-foot .gbar-dot{width:6px;height:6px;border-radius:50%;background:var(--dsw-alias-state-warn-primary);flex:none}
312
+ /* commit row inside the diff panel — height is drag-adjustable, so the message
313
+ field stretches to fill whatever the user gives this section. */
314
+ .gbar-side-commit{flex:none;min-height:0;overflow:hidden;display:flex;flex-direction:column;gap:7px;padding:9px 12px;border-top:1px solid var(--dsw-alias-border-l1)}
315
+ .gbar-side-commit .gbar-crow{flex:1;min-height:0;display:flex;align-items:stretch;gap:6px}
316
+ .gbar-side-commit textarea{
317
+ flex:1;min-width:0;min-height:30px;padding:6px 10px;resize:none;
318
+ border:1px solid var(--dsw-alias-border-l2);border-radius:8px;
319
+ background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);
320
+ font:inherit;font-size:12px;line-height:1.6;outline:none;overflow-y:auto;
321
+ }
322
+ .gbar-side-commit textarea:focus{border-color:var(--dsw-alias-state-business-primary)}
323
+ .gbar-side-commit textarea::placeholder{color:var(--dsw-alias-label-tertiary)}
324
+ .gbar-side-commit .gbar-actions{flex:none;display:flex;align-items:center;justify-content:flex-end;gap:6px}
325
+ .gbar-side-commit .gbar-btn{height:28px;padding:0 12px;font-size:12px;border-radius:8px}
326
+
327
+ /* commit modal */
328
+ .gbar-modal-wrap{
329
+ position:fixed;inset:0;z-index:120;
330
+ display:flex;align-items:center;justify-content:center;
331
+ background:rgba(0,0,0,.35);
332
+ }
333
+ .gbar-modal{
334
+ width:min(520px,calc(100vw - 40px));max-height:calc(100vh - 48px);overflow:hidden auto;
335
+ background:var(--dsw-alias-bg-layer-1);
336
+ border:1px solid var(--dsw-alias-border-l2);border-radius:16px;
337
+ box-shadow:var(--dsw-shadow-lv2);
338
+ padding:18px;
339
+ display:flex;flex-direction:column;gap:12px;
340
+ animation:gbar-in .18s cubic-bezier(.32,.72,0,1);
341
+ }
342
+ .gbar-modal .gbar-head{display:flex;align-items:center;gap:10px}
343
+ .gbar-modal .gbar-head .gbar-title{font-size:15px;font-weight:600}
344
+ .gbar-modal .gbar-head .gbar-branch{font-size:12px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-module-platform);border-radius:999px;padding:3px 10px}
345
+ .gbar-modal .gbar-head .gbar-x{margin-left:auto;border:none;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:16px;cursor:pointer;width:28px;height:28px;border-radius:8px}
346
+ .gbar-modal .gbar-head .gbar-x:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
347
+ .gbar-modal textarea{
348
+ width:100%;min-height:64px;height:auto;max-height:220px;resize:none;
349
+ overflow-y:auto;scrollbar-width:none;
350
+ border:1px solid var(--dsw-alias-border-l2);border-radius:12px;
351
+ background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);
352
+ font:inherit;font-size:14px;line-height:1.6;padding:10px 14px;outline:none;
353
+ }
354
+ .gbar-modal textarea::-webkit-scrollbar{display:none}
355
+ .gbar-modal textarea:focus{border-color:var(--dsw-alias-state-business-primary)}
356
+ .gbar-modal textarea::placeholder{color:var(--dsw-alias-label-tertiary)}
357
+ .gbar-modal .gbar-hint{font-size:12px;color:var(--dsw-alias-label-tertiary);line-height:1.6}
358
+ .gbar-modal .gbar-files-head{display:flex;align-items:center;gap:8px;font-size:11px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);margin-top:2px}
359
+ .gbar-modal .gbar-files-head .gbar-hint{font-size:11px;font-weight:400;text-transform:none;letter-spacing:0}
360
+ .gbar-modal .gbar-files{
361
+ display:flex;flex-direction:column;gap:1px;max-height:132px;overflow-y:auto;
362
+ border:1px solid var(--dsw-alias-border-l1);border-radius:10px;
363
+ background:var(--dsw-alias-bg-layer-2);padding:4px;
364
+ }
365
+ .gbar-modal .gbar-file{
366
+ display:flex;align-items:center;gap:6px;width:100%;
367
+ padding:2px 6px;border-radius:7px;background:transparent;
368
+ }
369
+ .gbar-modal .gbar-file .gbar-file-main{
370
+ padding:4px 4px;font-size:12px;border-radius:6px;
371
+ }
372
+ .gbar-modal .gbar-file .gbar-file-main:hover{background:var(--dsw-alias-interactive-bg-hover)}
373
+ .gbar-modal .gbar-file.gbar-on .gbar-file-main{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 10%,transparent)}
374
+ .gbar-modal .gbar-file .gbar-path{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--dsw-font-markdown-code-font-family,"SF Mono",Consolas,monospace);font-size:11.5px}
375
+ .gbar-modal .gbar-file .gbar-goto{flex:none;color:var(--dsw-alias-label-tertiary);font-size:10px}
376
+ .gbar-modal .gbar-file.gbar-on .gbar-goto{color:var(--dsw-alias-state-business-primary)}
377
+ .gbar-modal .gbar-foot{display:flex;align-items:center;justify-content:flex-end;gap:8px;margin-top:2px;flex-wrap:wrap}
378
+ .gbar-btn{
379
+ height:34px;padding:0 16px;border:none;border-radius:10px;
380
+ font:inherit;font-size:13.5px;cursor:pointer;
381
+ display:inline-flex;align-items:center;gap:6px;
382
+ }
383
+ .gbar-btn.gbar-ghost{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary)}
384
+ .gbar-btn.gbar-ghost:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}
385
+ .gbar-btn.gbar-soft{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary)}
386
+ .gbar-btn.gbar-soft:hover{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 18%,transparent)}
387
+ .gbar-btn.gbar-primary{background:var(--dsw-alias-state-business-primary);color:#fff;font-weight:500}
388
+ .gbar-btn.gbar-primary:hover{opacity:.92}
389
+ .gbar-btn:disabled{opacity:.5;cursor:default}
390
+ .gbar-notice{
391
+ position:fixed;z-index:150;left:50%;bottom:28px;transform:translateX(-50%);
392
+ max-width:min(520px,90vw);padding:9px 16px;border-radius:10px;font-size:12.5px;line-height:1.5;
393
+ box-shadow:var(--dsw-shadow-lv2);animation:gbar-in .18s cubic-bezier(.32,.72,0,1);
394
+ }
395
+ .gbar-notice.gbar-ok{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 16%,var(--dsw-alias-bg-layer-1));color:var(--dsw-alias-state-success-primary)}
396
+ .gbar-notice.gbar-err{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 14%,var(--dsw-alias-bg-layer-1));color:var(--dsw-alias-state-error-primary)}
397
+ .gbar-spin{width:12px;height:12px;border-radius:50%;border:2px solid color-mix(in srgb,var(--dsw-alias-label-tertiary) 30%,transparent);border-top-color:currentColor;animation:gbar-spin .7s linear infinite}
398
+ @keyframes gbar-spin{to{transform:rotate(360deg)}}
399
+ @media (prefers-reduced-motion:reduce){.gbar-side,.gbar-modal,.gbar-notice{animation:none}}
315
400
  `;
316
401
  /** Install the GitBar stylesheet once (idempotent); returns the disposer. */
317
402
  function installGitBarStyles() {
@@ -334,6 +419,10 @@ function shortBranch(name) {
334
419
  const idx = name.lastIndexOf('/');
335
420
  return idx >= 0 && name.startsWith('origin/') ? name.slice(idx + 1) : name;
336
421
  }
422
+ /** Branch names that must never be deletable (main/master). */
423
+ function isProtectedBranch(name) {
424
+ return name === 'main' || name === 'master';
425
+ }
337
426
  function statusLetter(status) {
338
427
  if (status === 'U')
339
428
  return 'U';
@@ -349,7 +438,7 @@ function statusClass(status) {
349
438
  return 'gbar-u';
350
439
  return 'gbar-m';
351
440
  }
352
- function GitBar({ sessionId, controller, t }) {
441
+ function GitBar({ sessionId, controller, sessionsService, t }) {
353
442
  const settingsState = (0, react_1.useSyncExternalStore)(controller.subscribe, controller.getSnapshot, controller.getSnapshot);
354
443
  const enabled = settingsState.value?.gitBarEnabled ?? true;
355
444
  const [snapshot, setSnapshot] = (0, react_1.useState)(null);
@@ -363,6 +452,15 @@ function GitBar({ sessionId, controller, t }) {
363
452
  const [busy, setBusy] = (0, react_1.useState)(null);
364
453
  const [notice, setNotice] = (0, react_1.useState)(null);
365
454
  const commitInputRef = (0, react_1.useRef)(null);
455
+ // Whether this session's agent is mid-turn. Committing while the model is
456
+ // still editing files would capture a half-written tree, so every commit
457
+ // entry point goes inert until the turn settles. `running` rides the same
458
+ // ConversationSnapshot the composer reads, so it flips without polling.
459
+ const liveSession = sessionId === undefined ? undefined : sessionsService.binding(sessionId)?.session;
460
+ const runStore = liveSession ?? NOOP_STORE;
461
+ const subscribeRun = (0, react_1.useMemo)(() => (fn) => runStore.subscribe(fn), [runStore]);
462
+ const readRun = (0, react_1.useMemo)(() => () => runStore.getSnapshot(), [runStore]);
463
+ const agentRunning = (0, react_1.useSyncExternalStore)(subscribeRun, readRun, readRun)?.running === true;
366
464
  // Auto-grow the commit message textarea so it never shows a scrollbar
367
465
  // (capped at 220px; beyond that the scrollbar is hidden entirely).
368
466
  const autoGrowCommitInput = () => {
@@ -467,10 +565,17 @@ function GitBar({ sessionId, controller, t }) {
467
565
  if (session === undefined || newBranchName.trim() === '')
468
566
  return;
469
567
  void run(pushToRemote ? 'create-push' : 'create', async () => {
470
- await apiPost(`${GIT_ROUTE}/create`, { session, name: newBranchName.trim(), push: pushToRemote });
568
+ await apiPost(`${GIT_ROUTE}/create`, {
569
+ session,
570
+ name: newBranchName.trim(),
571
+ base: baseBranch === '' ? undefined : baseBranch,
572
+ push: pushToRemote,
573
+ });
471
574
  setBranchOpen(false);
575
+ setNewBranchOpen(false);
472
576
  setNewBranchName('');
473
577
  setPushToRemote(false);
578
+ setBaseBranch('');
474
579
  await refresh();
475
580
  if (pushToRemote)
476
581
  showNotice('ok', `☁ ${newBranchName.trim()}`);
@@ -479,6 +584,15 @@ function GitBar({ sessionId, controller, t }) {
479
584
  const [newBranchName, setNewBranchName] = (0, react_1.useState)('');
480
585
  const [pushToRemote, setPushToRemote] = (0, react_1.useState)(false);
481
586
  const [confirmDelete, setConfirmDelete] = (0, react_1.useState)(null);
587
+ /** Base ref for the new-branch dialog: '' = current HEAD, otherwise a branch name. */
588
+ const [baseBranch, setBaseBranch] = (0, react_1.useState)('');
589
+ const [newBranchOpen, setNewBranchOpen] = (0, react_1.useState)(false);
590
+ const openNewBranch = () => {
591
+ setNewBranchName('');
592
+ setBaseBranch('');
593
+ setPushToRemote(false);
594
+ setNewBranchOpen(true);
595
+ };
482
596
  // Two-step branch deletion: first click arms a confirm, second click deletes.
483
597
  const deleteBranch = (name) => {
484
598
  if (session === undefined)
@@ -499,6 +613,43 @@ function GitBar({ sessionId, controller, t }) {
499
613
  }, 3000);
500
614
  }
501
615
  };
616
+ // Two-step remote-branch deletion (`git push origin --delete <branch>`).
617
+ const deleteRemoteBranch = (name) => {
618
+ if (session === undefined)
619
+ return;
620
+ if (confirmDelete === name) {
621
+ setConfirmDelete(null);
622
+ void run('remote-delete', async () => {
623
+ await apiPost(`${GIT_ROUTE}/remote-delete`, { session, name });
624
+ loadBranches();
625
+ await refresh();
626
+ showNotice('ok', `🗑 ${name}`);
627
+ });
628
+ }
629
+ else {
630
+ setConfirmDelete(name);
631
+ window.setTimeout(() => {
632
+ setConfirmDelete(current => (current === name ? null : current));
633
+ }, 3000);
634
+ }
635
+ };
636
+ // --- git commit graph dialog ------------------------------------------------
637
+ const [graphOpen, setGraphOpen] = (0, react_1.useState)(false);
638
+ const [graph, setGraph] = (0, react_1.useState)(null);
639
+ const [graphBusy, setGraphBusy] = (0, react_1.useState)(false);
640
+ const fetchGraph = () => {
641
+ if (session === undefined)
642
+ return;
643
+ setGraphBusy(true);
644
+ void apiGet(`${GIT_ROUTE}/graph?session=${encodeURIComponent(session)}&limit=150`)
645
+ .then(setGraph)
646
+ .catch(cause => { showNotice('err', cause instanceof Error ? cause.message : String(cause)); })
647
+ .finally(() => { setGraphBusy(false); });
648
+ };
649
+ const openGraph = () => {
650
+ setGraphOpen(true);
651
+ fetchGraph();
652
+ };
502
653
  // --- commit exclusions ----------------------------------------------------
503
654
  const [excluded, setExcluded] = (0, react_1.useState)(new Set());
504
655
  const toggleExclude = (path) => {
@@ -545,6 +696,14 @@ function GitBar({ sessionId, controller, t }) {
545
696
  // --- resizable diff panel -------------------------------------------------
546
697
  const [diffWidth, setDiffWidth] = (0, react_1.useState)(440);
547
698
  const [panelTop, setPanelTop] = (0, react_1.useState)(0);
699
+ // Section heights: `null` keeps the automatic sizing this panel shipped with
700
+ // (file list capped at FILES_AUTO_MAX, commit band hugging its content); a
701
+ // number is the height the user dragged that section to.
702
+ const [filesHeight, setFilesHeight] = (0, react_1.useState)(null);
703
+ const [commitHeight, setCommitHeight] = (0, react_1.useState)(null);
704
+ const [dragging, setDragging] = (0, react_1.useState)(null);
705
+ const [modalFilesHeight, setModalFilesHeight] = (0, react_1.useState)(null);
706
+ const [draggingModal, setDraggingModal] = (0, react_1.useState)(false);
548
707
  const branchRef = (0, react_1.useRef)(null);
549
708
  const branchPopRef = (0, react_1.useRef)(null);
550
709
  // The panel never covers the session header / message-area top edge: anchor
@@ -626,6 +785,66 @@ function GitBar({ sessionId, controller, t }) {
626
785
  window.addEventListener('pointermove', onMove);
627
786
  window.addEventListener('pointerup', onUp);
628
787
  };
788
+ // Drag a horizontal splitter to redistribute height between the panel's three
789
+ // sections. Only the dragged section gets an explicit height; the diff pane is
790
+ // the flexible one, so every pixel a neighbour gains comes out of the diff and
791
+ // the total never exceeds the panel. Double-click restores automatic sizing.
792
+ const startVResize = (target, event) => {
793
+ event.preventDefault();
794
+ const panel = document.querySelector('.gbar-side');
795
+ const measure = (selector) => {
796
+ const el = panel?.querySelector(selector) ?? null;
797
+ return el === null ? 0 : el.getBoundingClientRect().height;
798
+ };
799
+ const startY = event.clientY;
800
+ const startFiles = measure('.gbar-files');
801
+ const startCommit = measure('.gbar-side-commit');
802
+ const startDiff = measure('.gbar-diff');
803
+ setDragging(target);
804
+ const onMove = (move) => {
805
+ const delta = move.clientY - startY;
806
+ if (target === 'files') {
807
+ // Dragging down grows the file list and shrinks the diff.
808
+ const ceiling = Math.max(MIN_FILES_H, startFiles + startDiff - MIN_DIFF_H);
809
+ setFilesHeight(Math.round(Math.min(ceiling, Math.max(MIN_FILES_H, startFiles + delta))));
810
+ }
811
+ else {
812
+ // Dragging up grows the commit band and shrinks the diff.
813
+ const ceiling = Math.max(MIN_COMMIT_H, startCommit + startDiff - MIN_DIFF_H);
814
+ setCommitHeight(Math.round(Math.min(ceiling, Math.max(MIN_COMMIT_H, startCommit - delta))));
815
+ }
816
+ };
817
+ const onUp = () => {
818
+ setDragging(null);
819
+ window.removeEventListener('pointermove', onMove);
820
+ window.removeEventListener('pointerup', onUp);
821
+ };
822
+ window.addEventListener('pointermove', onMove);
823
+ window.addEventListener('pointerup', onUp);
824
+ };
825
+ // Drag the file list header in the commit modal to reveal more files without
826
+ // scrolling. The modal is portal-rendered, so this targets `.gbar-modal`
827
+ // directly; double-click snaps back to the default cap.
828
+ const startModalVResize = (event) => {
829
+ event.preventDefault();
830
+ const modal = document.querySelector('.gbar-modal');
831
+ const files = modal?.querySelector('.gbar-modal .gbar-files') ?? null;
832
+ const startY = event.clientY;
833
+ const startH = files === null ? MODAL_FILES_AUTO_MAX : files.getBoundingClientRect().height;
834
+ setModalFilesHeight(startH);
835
+ setDraggingModal(true);
836
+ const onMove = (move) => {
837
+ const next = Math.max(48, Math.min(360, startH + (move.clientY - startY)));
838
+ setModalFilesHeight(Math.round(next));
839
+ };
840
+ const onUp = () => {
841
+ setDraggingModal(false);
842
+ window.removeEventListener('pointermove', onMove);
843
+ window.removeEventListener('pointerup', onUp);
844
+ };
845
+ window.addEventListener('pointermove', onMove);
846
+ window.addEventListener('pointerup', onUp);
847
+ };
629
848
  // Push the conversation column left while the panel is open, so the user's
630
849
  // timeline rail (anchored to the message-area right edge) stays visible.
631
850
  (0, react_1.useEffect)(() => {
@@ -638,25 +857,21 @@ function GitBar({ sessionId, controller, t }) {
638
857
  root.style.marginRight = ''; };
639
858
  }, [diffOpen, diffWidth]);
640
859
  const openCommit = () => {
860
+ // Inert while the agent is mid-turn (the pill is disabled too; this guards
861
+ // a turn that starts between render and click).
862
+ if (agentRunning)
863
+ return;
641
864
  setCommitOpen(true);
642
865
  void refresh();
643
866
  };
644
- const generateMessage = () => {
645
- if (session === undefined || busy !== null)
646
- return;
647
- void run('suggest', async () => {
648
- const result = await apiPost(`${GIT_ROUTE}/suggest`, { session });
649
- setMessage(result.message);
650
- });
651
- };
652
867
  const doCommit = (push) => {
653
- if (session === undefined)
868
+ if (session === undefined || agentRunning)
654
869
  return;
655
870
  void run(push ? 'commit-push' : 'commit', async () => {
656
- let msg = message.trim();
871
+ const msg = message.trim();
657
872
  if (msg === '') {
658
- const result = await apiPost(`${GIT_ROUTE}/suggest`, { session });
659
- msg = result.message;
873
+ showNotice('err', t('commitEmpty'));
874
+ return;
660
875
  }
661
876
  const result = await apiPost(`${GIT_ROUTE}/commit`, {
662
877
  session,
@@ -678,13 +893,20 @@ function GitBar({ sessionId, controller, t }) {
678
893
  return null;
679
894
  const dirty = !snapshot.clean;
680
895
  const diffPillOpen = diffOpen;
681
- return ((0, jsx_runtime_1.jsxs)("div", { className: "gbar", "data-slot-plugin": "dsh-ui-tweaks-gitbar", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", ref: branchRef, className: 'gbar-pill' + (branchOpen ? ' gbar-active' : ''), onClick: toggleBranch, title: dirty ? t('dirty') : t('clean'), "aria-expanded": branchOpen, children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-ico", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M7.4 2.6a1.2 1.2 0 1 1 2.2 0l3.2 1.6a1.2 1.2 0 1 1-1.1 2.1l-2.3-1.2a2.6 2.6 0 0 1-1.1.8l.6 4.2a1.2 1.2 0 1 1-1.7.2l-.6-4.2a2.6 2.6 0 0 1-1.2-.7l-2.9 1.5a1.2 1.2 0 1 1-1.1-2.1l2.9-1.5a2.6 2.6 0 0 1 .2-1.5l-3.2-1.6a1.2 1.2 0 1 1 1.1-2.1z" }) }), (0, jsx_runtime_1.jsx)("span", { children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), dirty ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-dot", "aria-hidden": true }) : null, (0, jsx_runtime_1.jsx)("span", { className: "gbar-caret", "aria-hidden": true, children: "\u25BE" })] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-right", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-pill' + (diffPillOpen ? ' gbar-active' : ''), onClick: openDiff, title: t('diffTitle'), children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-ico", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M5 1.5h4l3 3V13a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 13V3A1.5 1.5 0 0 1 5 1.5zM5 2.5V13h5V5.2L8.8 3.5H5zm.5 4.5a.75.75 0 1 1 0 1.5.75.75 0 0 1 0-1.5zm3.25.25h-1.5v1.5h1.5V7.25zm.25 2.5H5.75v1.5h3.25v-1.5z" }) }), dirty ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-add", children: ["+", snapshot.totalAdded] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-del", children: ["\u2212", snapshot.totalDeleted] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-meta", children: ["\u00B7 ", snapshot.files.length, " ", t('diffFiles')] })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "gbar-hint", children: t('clean') }))] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-pill", onClick: openCommit, title: t('commitTitle'), children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-ico", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M11.4 1.6a2.12 2.12 0 0 1 3 3l-8 8-3.4.8.8-3.4 7.6-8.4zM12.1 2.3l.9.9-7.6 8.3-.8.2.2-.8 7.3-8.6z" }) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-hint", children: t('commitMessage') })] })] }), branchOpen ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop", role: "menu", "aria-label": snapshot.branch ?? 'git', ref: branchPopRef, children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-sec", children: t('branchLocal') }), branches?.local.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsx)("span", { children: name }), name === branches.current ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-check", "aria-hidden": true, children: "\u2713" }) : null] }), name !== branches.current ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteBranch(name); }, title: t('branchDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : '🗑' })) : null] }, name))), (0, jsx_runtime_1.jsx)("div", { className: "gbar-sec", children: t('branchRemote') }), branches?.remote.map(name => ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsx)("span", { children: shortBranch(name) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-rm", children: name.split('/')[0] })] }, name))), (0, jsx_runtime_1.jsx)("div", { className: "gbar-sec", children: t('branchNew') }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-newrow", children: [(0, jsx_runtime_1.jsx)("input", { value: newBranchName, onChange: event => { setNewBranchName(event.target.value); }, onKeyDown: event => { if (event.key === 'Enter')
682
- createBranch(); }, placeholder: t('branchNewPlaceholder'), "aria-label": t('branchNew') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-mini", onClick: createBranch, disabled: busy !== null || newBranchName.trim() === '', children: t('branchCreate') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-pushrow", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-chk' + (pushToRemote ? '' : ' gbar-off'), onClick: () => { setPushToRemote(value => !value); }, "aria-label": t('branchPushRemote'), children: pushToRemote ? '✓' : '✕' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-pushlabel", children: t('branchPushRemote') })] })] })) : null, diffOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsxs)("div", { className: "gbar-side", role: "dialog", "aria-label": t('diffTitle'), style: { width: `${diffWidth}px`, top: `${panelTop}px` }, children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-resize", onPointerDown: startResize, title: "\u62D6\u52A8\u8C03\u6574\u5BBD\u5EA6" }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: diffPath ?? t('diffTitle') }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-sub", children: [snapshot.files.length, " ", t('diffFiles'), " \u00B7 +", snapshot.totalAdded, " \u2212", snapshot.totalDeleted] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-spacer" }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-seg", role: "group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: diffMode === 'hunk' ? 'gbar-on' : '', onClick: () => { switchDiffMode('hunk'); }, children: t('diffOnly') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: diffMode === 'full' ? 'gbar-on' : '', onClick: () => { switchDiffMode('full'); }, children: t('diffFull') })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-side-x", onClick: () => { setDiffOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-body", children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-files", children: snapshot.files.map(file => {
896
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "gbar", "data-slot-plugin": "dsh-ui-tweaks-gitbar", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", ref: branchRef, className: 'gbar-pill' + (branchOpen ? ' gbar-active' : ''), onClick: toggleBranch, title: dirty ? t('dirty') : t('clean'), "aria-expanded": branchOpen, children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-ico", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M7.4 2.6a1.2 1.2 0 1 1 2.2 0l3.2 1.6a1.2 1.2 0 1 1-1.1 2.1l-2.3-1.2a2.6 2.6 0 0 1-1.1.8l.6 4.2a1.2 1.2 0 1 1-1.7.2l-.6-4.2a2.6 2.6 0 0 1-1.2-.7l-2.9 1.5a1.2 1.2 0 1 1-1.1-2.1l2.9-1.5a2.6 2.6 0 0 1 .2-1.5l-3.2-1.6a1.2 1.2 0 1 1 1.1-2.1z" }) }), (0, jsx_runtime_1.jsx)("span", { children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-caret", "aria-hidden": true, children: "\u25BE" })] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-right", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-pill' + (diffPillOpen ? ' gbar-active' : ''), onClick: openDiff, title: t('diffTitle'), children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-ico", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M5 1.5h4l3 3V13a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 13V3A1.5 1.5 0 0 1 5 1.5zM5 2.5V13h5V5.2L8.8 3.5H5zm.5 4.5a.75.75 0 1 1 0 1.5.75.75 0 0 1 0-1.5zm3.25.25h-1.5v1.5h1.5V7.25zm.25 2.5H5.75v1.5h3.25v-1.5z" }) }), dirty ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-add", children: ["+", snapshot.totalAdded] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-del", children: ["\u2212", snapshot.totalDeleted] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-meta", children: ["\u00B7 ", snapshot.files.length, " ", t('diffFiles')] })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "gbar-hint", children: t('clean') }))] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-pill", onClick: openCommit, disabled: agentRunning, "aria-disabled": agentRunning, title: agentRunning ? '模型正在工作,暂不能提交' : t('commitTitle'), children: [(0, jsx_runtime_1.jsx)("svg", { className: "gbar-ico", viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M11.4 1.6a2.12 2.12 0 0 1 3 3l-8 8-3.4.8.8-3.4 7.6-8.4zM12.1 2.3l.9.9-7.6 8.3-.8.2.2-.8 7.3-8.6z" }) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-hint", children: t('commitMessage') }), dirty ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-dot", "aria-hidden": true }) : null] })] }), branchOpen ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-pop", role: "menu", "aria-label": snapshot.branch ?? 'git', ref: branchPopRef, children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-sec", children: t('branchLocal') }), branches?.local.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsx)("span", { children: name }), name === branches.current ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-check", "aria-hidden": true, children: "\u2713" }) : null] }), name !== branches.current && !isProtectedBranch(name) ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteBranch(name); }, title: t('branchDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : '🗑' })) : null] }, name))), (0, jsx_runtime_1.jsx)("div", { className: "gbar-sec", children: t('branchRemote') }), branches?.remote.map(name => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-rowwrap", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: 'gbar-row' + (name === branches.current ? ' gbar-cur' : ''), onClick: () => { pickBranch(name); }, children: [(0, jsx_runtime_1.jsx)("span", { children: shortBranch(name) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-rm", children: name.split('/')[0] })] }), !isProtectedBranch(shortBranch(name)) ? ((0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-del' + (confirmDelete === name ? ' gbar-arm' : ''), onClick: () => { deleteRemoteBranch(name); }, title: t('branchRemoteDelete'), children: confirmDelete === name ? t('branchDeleteConfirm') : '🗑' })) : null] }, name))), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-act", onClick: openNewBranch, children: [(0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": true, children: (0, jsx_runtime_1.jsx)("path", { d: "M7.4 2.6a1.2 1.2 0 1 1 2.2 0l3.2 1.6a1.2 1.2 0 1 1-1.1 2.1l-2.3-1.2a2.6 2.6 0 0 1-1.1.8l.6 4.2a1.2 1.2 0 1 1-1.7.2l-.6-4.2a2.6 2.6 0 0 1-1.2-.7l-2.9 1.5a1.2 1.2 0 1 1-1.1-2.1l2.9-1.5a2.6 2.6 0 0 1 .2-1.5l-3.2-1.6a1.2 1.2 0 1 1 1.1-2.1z" }) }), t('branchNew')] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-act", onClick: openGraph, children: [(0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M3 1.5v3.4a4.4 4.4 0 0 0 4.4 4.4h5.1" }), (0, jsx_runtime_1.jsx)("path", { d: "M13 1.5v4.9a3.2 3.2 0 0 1-3.2 3.2H3" }), (0, jsx_runtime_1.jsx)("circle", { cx: "3", cy: "1.5", r: "1.2", fill: "currentColor", stroke: "none" }), (0, jsx_runtime_1.jsx)("circle", { cx: "13", cy: "12", r: "1.2", fill: "currentColor", stroke: "none" })] }), t('branchGraph')] })] })] })) : null, diffOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsxs)("div", { className: "gbar-side", role: "dialog", "aria-label": t('diffTitle'), style: { width: `${diffWidth}px`, top: `${panelTop}px` }, children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-resize", onPointerDown: startResize, title: "\u62D6\u52A8\u8C03\u6574\u5BBD\u5EA6" }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: diffPath ?? t('diffTitle') }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-sub", children: [snapshot.files.length, " ", t('diffFiles'), " \u00B7 +", snapshot.totalAdded, " \u2212", snapshot.totalDeleted] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-spacer" }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-seg", role: "group", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: diffMode === 'hunk' ? 'gbar-on' : '', onClick: () => { switchDiffMode('hunk'); }, children: t('diffOnly') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: diffMode === 'full' ? 'gbar-on' : '', onClick: () => { switchDiffMode('full'); }, children: t('diffFull') })] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-side-x", onClick: () => { setDiffOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-body", children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-files", style: filesHeight === null
897
+ ? { maxHeight: FILES_AUTO_MAX }
898
+ : { height: filesHeight, maxHeight: SECTION_MAX }, children: snapshot.files.map(file => {
683
899
  const isExcluded = excluded.has(file.path);
684
900
  return ((0, jsx_runtime_1.jsxs)("div", { className: 'gbar-file' + (diffPath === file.path ? ' gbar-on' : '') + (isExcluded ? ' gbar-excl' : ''), children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-chk' + (isExcluded ? ' gbar-off' : ''), onClick: () => { toggleExclude(file.path); }, "aria-label": isExcluded ? t('excludeFile') : t('includeFile'), children: isExcluded ? '✕' : '✓' }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-file-main", onClick: () => { selectDiffFile(file.path); }, children: [(0, jsx_runtime_1.jsx)("span", { className: 'gbar-st ' + statusClass(file.status), children: statusLetter(file.status) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-path", children: file.path }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-nums", children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-a", children: ["+", file.added] }), " ", (0, jsx_runtime_1.jsxs)("span", { className: "gbar-d", children: ["\u2212", file.deleted] })] })] })] }, file.path));
685
- }) }), diff === null ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-diff", children: (0, jsx_runtime_1.jsx)("div", { className: "gbar-empty", children: t('loading') }) })) : diff.lines.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-diff", children: (0, jsx_runtime_1.jsx)("div", { className: "gbar-empty", children: t('noChanges') }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-diff", children: [diff.lines.map((line, i) => ((0, jsx_runtime_1.jsxs)("div", { className: 'gbar-line gbar-' + line.type, children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-ln", children: line.old ?? '' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-ln", children: line.new ?? '' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-code", children: line.text })] }, i))), diff.truncated ? (0, jsx_runtime_1.jsx)("div", { className: "gbar-empty", children: "\u2026" }) : null] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-foot", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-dot" }), snapshot.branch ?? '—', " \u00B7 ", dirty ? t('dirty') : t('clean')] }), dirty ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-commit", children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-crow", children: (0, jsx_runtime_1.jsx)("input", { value: message, onChange: event => { setMessage(event.target.value); }, onKeyDown: event => { if (event.key === 'Enter' && !event.shiftKey)
686
- doCommit(false); }, placeholder: t('commitPlaceholder'), "aria-label": t('commitMessage') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-actions", children: [(0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-btn gbar-ghost", onClick: generateMessage, disabled: busy !== null, children: [busy === 'suggest' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : null, t('commitGenerate')] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-btn gbar-soft", onClick: () => { doCommit(false); }, disabled: busy !== null, children: t('commitSubmit') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-btn gbar-primary", onClick: () => { doCommit(true); }, disabled: busy !== null, children: t('commitSubmitPush') })] })] })) : null] }), document.body) : null, commitOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: "gbar-modal-wrap", onMouseDown: event => { if (event.target === event.currentTarget)
687
- setCommitOpen(false); }, children: (0, jsx_runtime_1.jsxs)("div", { className: "gbar-modal", role: "dialog", "aria-label": t('commitTitle'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: t('commitTitle') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-branch", children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x", onClick: () => { setCommitOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), (0, jsx_runtime_1.jsx)("textarea", { ref: commitInputRef, value: message, onChange: event => { setMessage(event.target.value); }, placeholder: t('commitPlaceholder'), autoFocus: true }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-files-head", children: [t('commitWillCommit'), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-hint", children: ["\u00B7 ", snapshot.files.length - excluded.size, " ", t('diffFiles')] })] }), (0, jsx_runtime_1.jsx)("div", { className: "gbar-files", children: snapshot.files.map(file => {
901
+ }) }), (0, jsx_runtime_1.jsx)("div", { className: 'gbar-vsplit' + (dragging === 'files' ? ' gbar-dragging' : ''), role: "separator", "aria-orientation": "horizontal", title: "\u62D6\u52A8\u8C03\u6574\u6587\u4EF6\u5217\u8868\u9AD8\u5EA6\uFF08\u53CC\u51FB\u590D\u4F4D\uFF09", onPointerDown: event => { startVResize('files', event); }, onDoubleClick: () => { setFilesHeight(null); } }), diff === null ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-diff", children: (0, jsx_runtime_1.jsx)("div", { className: "gbar-empty", children: t('loading') }) })) : diff.lines.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-diff", children: (0, jsx_runtime_1.jsx)("div", { className: "gbar-empty", children: t('noChanges') }) })) : ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-diff", children: [diff.lines.map((line, i) => ((0, jsx_runtime_1.jsxs)("div", { className: 'gbar-line gbar-' + line.type, children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-ln", children: line.old ?? '' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-ln", children: line.new ?? '' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-code", children: line.text })] }, i))), diff.truncated ? (0, jsx_runtime_1.jsx)("div", { className: "gbar-empty", children: "\u2026" }) : null] })), dirty ? ((0, jsx_runtime_1.jsx)("div", { className: 'gbar-vsplit' + (dragging === 'commit' ? ' gbar-dragging' : ''), role: "separator", "aria-orientation": "horizontal", title: "\u62D6\u52A8\u8C03\u6574\u63D0\u4EA4\u533A\u9AD8\u5EA6\uFF08\u53CC\u51FB\u590D\u4F4D\uFF09", onPointerDown: event => { startVResize('commit', event); }, onDoubleClick: () => { setCommitHeight(null); } })) : null] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-foot", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-dot" }), snapshot.branch ?? '—', " \u00B7 ", dirty ? t('dirty') : t('clean')] }), dirty ? ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-side-commit", style: commitHeight === null ? undefined : { height: commitHeight, maxHeight: SECTION_MAX }, children: [(0, jsx_runtime_1.jsx)("div", { className: "gbar-crow", children: (0, jsx_runtime_1.jsx)("textarea", { value: message, onChange: event => { setMessage(event.target.value); }, onKeyDown: event => {
902
+ // Enter commits; Shift+Enter adds a line, now that this field
903
+ // can be dragged tall enough for a multi-line message.
904
+ if (event.key === 'Enter' && !event.shiftKey) {
905
+ event.preventDefault();
906
+ doCommit(false);
907
+ }
908
+ }, placeholder: t('commitPlaceholder'), "aria-label": t('commitMessage'), rows: 1 }) }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-actions", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-btn gbar-soft", onClick: () => { doCommit(false); }, disabled: busy !== null || agentRunning, children: t('commitSubmit') }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-btn gbar-primary", onClick: () => { doCommit(true); }, disabled: busy !== null || agentRunning, children: t('commitSubmitPush') })] })] })) : null] }), document.body) : null, commitOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: "gbar-modal-wrap", onMouseDown: event => { if (event.target === event.currentTarget)
909
+ setCommitOpen(false); }, children: (0, jsx_runtime_1.jsxs)("div", { className: "gbar-modal", role: "dialog", "aria-label": t('commitTitle'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: t('commitTitle') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-branch", children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x", onClick: () => { setCommitOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), (0, jsx_runtime_1.jsx)("textarea", { ref: commitInputRef, value: message, onChange: event => { setMessage(event.target.value); }, placeholder: t('commitPlaceholder'), autoFocus: true }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-files-head", children: [t('commitWillCommit'), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-hint", children: ["\u00B7 ", snapshot.files.length - excluded.size, " ", t('diffFiles')] })] }), (0, jsx_runtime_1.jsx)("div", { className: "gbar-files", style: modalFilesHeight === null ? undefined : { height: modalFilesHeight, maxHeight: 'none' }, children: snapshot.files.map(file => {
688
910
  const isExcluded = excluded.has(file.path);
689
911
  return ((0, jsx_runtime_1.jsxs)("div", { className: 'gbar-file' + (isExcluded ? ' gbar-excl' : ''), children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-chk' + (isExcluded ? ' gbar-off' : ''), onClick: () => { toggleExclude(file.path); }, "aria-label": isExcluded ? t('excludeFile') : t('includeFile'), children: isExcluded ? '✕' : '✓' }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-file-main", onClick: () => {
690
912
  setDiffPath(file.path);
@@ -692,7 +914,10 @@ function GitBar({ sessionId, controller, t }) {
692
914
  setDiffOpen(true);
693
915
  setCommitOpen(false);
694
916
  }, children: [(0, jsx_runtime_1.jsx)("span", { className: 'gbar-st ' + statusClass(file.status), children: statusLetter(file.status) }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-path", children: file.path }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-nums", children: [(0, jsx_runtime_1.jsxs)("span", { className: "gbar-a", children: ["+", file.added] }), " ", (0, jsx_runtime_1.jsxs)("span", { className: "gbar-d", children: ["\u2212", file.deleted] })] }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-goto", children: [t('commitViewDiff'), " \u203A"] })] })] }, file.path));
695
- }) }), (0, jsx_runtime_1.jsx)("div", { className: "gbar-hint", children: t('commitHint') }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-foot", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-btn gbar-ghost", onClick: () => { setCommitOpen(false); }, children: t('commitCancel') }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-btn gbar-ghost", onClick: generateMessage, disabled: busy !== null, children: [busy === 'suggest' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : null, t('commitGenerate')] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-btn gbar-soft", onClick: () => { doCommit(false); }, disabled: busy !== null, children: [busy === 'commit' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : null, " ", t('commitSubmit')] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-btn gbar-primary", onClick: () => { doCommit(true); }, disabled: busy !== null, children: [busy === 'commit-push' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : null, " ", t('commitSubmitPush')] })] })] }) }), document.body) : null, notice !== null ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: 'gbar-notice gbar-' + notice.kind, role: "status", children: notice.text }), document.body) : null] }));
917
+ }) }), (0, jsx_runtime_1.jsx)("div", { className: "gbar-vsplit" + (draggingModal ? " gbar-dragging" : ""), role: "separator", "aria-orientation": "horizontal", title: "\u62D6\u52A8\u8C03\u6574\u6587\u4EF6\u5217\u8868\u9AD8\u5EA6", onPointerDown: startModalVResize, onDoubleClick: () => { setModalFilesHeight(null); } }), (0, jsx_runtime_1.jsx)("div", { className: "gbar-hint", children: t('commitHint') }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-foot", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-btn gbar-ghost", onClick: () => { setCommitOpen(false); }, children: t('commitCancel') }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-btn gbar-soft", onClick: () => { doCommit(false); }, disabled: busy !== null || agentRunning, children: [busy === 'commit' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : null, " ", t('commitSubmit')] }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-btn gbar-primary", onClick: () => { doCommit(true); }, disabled: busy !== null || agentRunning, children: [busy === 'commit-push' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : null, " ", t('commitSubmitPush')] })] })] }) }), document.body) : null, newBranchOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: "gbar-modal-wrap", onMouseDown: event => { if (event.target === event.currentTarget)
918
+ setNewBranchOpen(false); }, children: (0, jsx_runtime_1.jsxs)("div", { className: "gbar-modal", role: "dialog", "aria-label": t('branchNew'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: t('branchNew') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-branch", children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x", onClick: () => { setNewBranchOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), (0, jsx_runtime_1.jsx)("input", { value: newBranchName, onChange: event => { setNewBranchName(event.target.value); }, onKeyDown: event => { if (event.key === 'Enter')
919
+ createBranch(); }, placeholder: t('branchNewPlaceholder'), "aria-label": t('branchNew'), autoFocus: true }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-baserow", children: [(0, jsx_runtime_1.jsx)("label", { className: "gbar-baselabel", htmlFor: "gbar-base-dlg", children: t('branchFrom') }), (0, jsx_runtime_1.jsxs)("select", { id: "gbar-base-dlg", className: "gbar-base", value: baseBranch, onChange: event => { setBaseBranch(event.target.value); }, "aria-label": t('branchFrom'), children: [(0, jsx_runtime_1.jsx)("option", { value: "", children: t('branchFromHead') }), branches?.local.map(name => (0, jsx_runtime_1.jsx)("option", { value: name, children: name }, name)), branches?.remote.map(name => (0, jsx_runtime_1.jsx)("option", { value: name, children: name }, name))] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-pushrow", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: 'gbar-chk' + (pushToRemote ? '' : ' gbar-off'), onClick: () => { setPushToRemote(value => !value); }, "aria-label": t('branchPushRemote'), children: pushToRemote ? '✓' : '✕' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-pushlabel", children: t('branchPushRemote') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "gbar-foot", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-btn gbar-ghost", onClick: () => { setNewBranchOpen(false); }, children: t('branchCancel') }), (0, jsx_runtime_1.jsxs)("button", { type: "button", className: "gbar-btn gbar-primary", onClick: createBranch, disabled: busy !== null || newBranchName.trim() === '', children: [busy === 'create' || busy === 'create-push' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : null, " ", t('branchCreate')] })] })] }) }), document.body) : null, graphOpen ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: "gbar-modal-wrap", onMouseDown: event => { if (event.target === event.currentTarget)
920
+ setGraphOpen(false); }, children: (0, jsx_runtime_1.jsxs)("div", { className: "gbar-modal gbar-graph-modal", role: "dialog", "aria-label": t('graphTitle'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-head", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-title", children: t('graphTitle') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-branch", children: snapshot.branch ?? snapshot.detachedHead ?? '—' }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-spacer" }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x gbar-refresh", onClick: fetchGraph, "aria-label": t('branchRefresh'), title: t('branchRefresh'), disabled: graphBusy, children: graphBusy ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-spin" }) : ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 16 16", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": true, children: [(0, jsx_runtime_1.jsx)("path", { d: "M13.4 8a5.4 5.4 0 1 1-1.6-3.8" }), (0, jsx_runtime_1.jsx)("path", { d: "M13.4 1.5v3h-3" })] })) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "gbar-x", onClick: () => { setGraphOpen(false); }, "aria-label": "\u2715", children: "\u2715" })] }), graph === null ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-graph-empty", children: graphBusy ? t('loading') : t('noChanges') })) : graph.commits.length === 0 ? ((0, jsx_runtime_1.jsx)("div", { className: "gbar-graph-empty", children: t('noChanges') })) : ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-graph-table", role: "table", "aria-label": t('graphTitle'), children: [(0, jsx_runtime_1.jsxs)("div", { className: "gbar-graph-row gbar-graph-head", role: "row", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-c-hash", role: "columnheader", children: t('graphColCommit') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-subject", role: "columnheader", children: t('graphColSubject') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-author", role: "columnheader", children: t('graphColAuthor') }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-date", role: "columnheader", children: t('graphColDate') })] }), graph.commits.map(commit => ((0, jsx_runtime_1.jsxs)("div", { className: "gbar-graph-row", role: "row", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-c-hash", role: "cell", children: (0, jsx_runtime_1.jsx)("code", { className: "gbar-hash", children: commit.hash }) }), (0, jsx_runtime_1.jsxs)("span", { className: "gbar-c-subject", role: "cell", children: [(0, jsx_runtime_1.jsx)("span", { className: "gbar-subject", children: commit.subject }), commit.refs !== '' ? (0, jsx_runtime_1.jsx)("span", { className: "gbar-refs", children: commit.refs }) : null] }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-author", role: "cell", children: commit.author }), (0, jsx_runtime_1.jsx)("span", { className: "gbar-c-date", role: "cell", title: commit.date, children: commit.dateRelative })] }, commit.fullHash)))] }))] }) }), document.body) : null, notice !== null ? (0, react_dom_1.createPortal)((0, jsx_runtime_1.jsx)("div", { className: 'gbar-notice gbar-' + notice.kind, role: "status", children: notice.text }), document.body) : null] }));
696
921
  }
697
922
  };
698
923
  __modules["./index.js"] = function(module, exports, require, __load_) {
@@ -757,7 +982,7 @@ const en = {
757
982
  loading: 'Loading…',
758
983
  readOnly: 'The active Settings provider is read-only.',
759
984
  saved: 'Saved.',
760
- commitMessage: 'commit message',
985
+ commitMessage: 'Commit',
761
986
  diffFiles: 'files',
762
987
  branchLocal: 'Local branches',
763
988
  branchRemote: 'Remote branches',
@@ -768,11 +993,11 @@ const en = {
768
993
  diffOnly: 'Hunks',
769
994
  diffFull: 'Full file',
770
995
  commitTitle: 'Commit changes',
771
- commitPlaceholder: 'Describe your changes…\nLeave empty to auto-generate',
996
+ commitPlaceholder: 'Describe your changes…',
772
997
  commitHint: 'Committing stages the checked files (untracked included) and commits; unchecked files are excluded from this commit. “Commit & push” also pushes; a new branch gets an -u upstream.',
773
998
  commitWillCommit: 'To commit',
774
999
  commitViewDiff: 'View',
775
- commitGenerate: '✨ Generate',
1000
+ commitEmpty: 'Write a commit message first',
776
1001
  commitCancel: 'Cancel',
777
1002
  commitSubmit: 'Commit',
778
1003
  commitSubmitPush: 'Commit & push',
@@ -781,6 +1006,18 @@ const en = {
781
1006
  noChanges: 'No changes here.',
782
1007
  branchDelete: 'Delete branch',
783
1008
  branchDeleteConfirm: 'Confirm?',
1009
+ branchRemoteDelete: 'Delete remote branch',
1010
+ branchFrom: 'From branch',
1011
+ branchFromHead: 'Current HEAD (default)',
1012
+ branchGraph: 'Graph',
1013
+ branchCancel: 'Cancel',
1014
+ branchRefresh: 'Refresh',
1015
+ graphTitle: 'Commit graph',
1016
+ graphColGraph: 'Graph',
1017
+ graphColCommit: 'Commit',
1018
+ graphColSubject: 'Description',
1019
+ graphColAuthor: 'Author',
1020
+ graphColDate: 'Date',
784
1021
  branchPushRemote: 'Push to remote',
785
1022
  includeFile: 'Include in commit',
786
1023
  excludeFile: 'Exclude from commit',
@@ -821,7 +1058,7 @@ const zh = {
821
1058
  loading: '加载中…',
822
1059
  readOnly: '当前设置提供方为只读。',
823
1060
  saved: '已保存。',
824
- commitMessage: 'commit message',
1061
+ commitMessage: 'Commit',
825
1062
  diffFiles: '个文件',
826
1063
  branchLocal: '本地分支',
827
1064
  branchRemote: '远程分支',
@@ -832,11 +1069,11 @@ const zh = {
832
1069
  diffOnly: '仅差异',
833
1070
  diffFull: '完整文件',
834
1071
  commitTitle: '提交变更',
835
- commitPlaceholder: '描述你的改动…\n留空点「提交」将根据改动内容自动生成',
1072
+ commitPlaceholder: '描述你的改动…',
836
1073
  commitHint: '提交会暂存勾选的文件(含未跟踪新文件);取消勾选的文件将不包含在本次提交中。「提交并推送」提交后自动 push,新分支自动 -u 设上游。',
837
1074
  commitWillCommit: '将提交',
838
1075
  commitViewDiff: '查看',
839
- commitGenerate: '✨ 生成',
1076
+ commitEmpty: '请先填写提交说明',
840
1077
  commitCancel: '取消',
841
1078
  commitSubmit: '提交',
842
1079
  commitSubmitPush: '提交并推送',
@@ -845,6 +1082,18 @@ const zh = {
845
1082
  noChanges: '这里没有差异。',
846
1083
  branchDelete: '删除分支',
847
1084
  branchDeleteConfirm: '确认删除?',
1085
+ branchRemoteDelete: '删除远程分支',
1086
+ branchFrom: '基于分支',
1087
+ branchFromHead: '当前 HEAD(默认)',
1088
+ branchGraph: '图谱',
1089
+ branchCancel: '取消',
1090
+ branchRefresh: '刷新',
1091
+ graphTitle: '提交图谱',
1092
+ graphColGraph: '图',
1093
+ graphColCommit: '提交',
1094
+ graphColSubject: '描述',
1095
+ graphColAuthor: '作者',
1096
+ graphColDate: '日期',
848
1097
  branchPushRemote: '推送到远程',
849
1098
  includeFile: '提交包含此文件',
850
1099
  excludeFile: '提交排除此文件',
@@ -904,38 +1153,38 @@ function buildFontCss(fontSize) {
904
1153
  * follow the message font-size setting. Alignment is left to the markdown
905
1154
  * renderer, so headers and cells always match.
906
1155
  */
907
- const CLAUDE_TABLE_CSS = `
908
- div[data-slot="conversation.chat.node"] table{
909
- border-collapse:separate !important;
910
- border-spacing:3px !important;
911
- width:100% !important;
912
- border:none !important;
913
- font-size:var(--dsw-font-markdown-base-font-size) !important;
914
- }
915
- div[data-slot="conversation.chat.node"] table thead th{
916
- background:var(--dsw-alias-markdown-inline-code) !important;
917
- color:inherit !important;
918
- font-weight:400 !important;
919
- font-size:inherit !important;
920
- padding:7px 10px !important;
921
- border:none !important;
922
- border-radius:6px !important;
923
- }
924
- div[data-slot="conversation.chat.node"] table tbody td{
925
- background:var(--dsw-alias-markdown-inline-code) !important;
926
- color:inherit !important;
927
- font-size:inherit !important;
928
- padding:7px 10px !important;
929
- vertical-align:top !important;
930
- border:none !important;
931
- border-radius:6px !important;
932
- }
933
- div[data-slot="conversation.chat.node"] table code,
934
- div[data-slot="conversation.chat.node"] table pre{
935
- background:transparent !important;
936
- border:none !important;
937
- box-shadow:none !important;
938
- }
1156
+ const CLAUDE_TABLE_CSS = `
1157
+ div[data-slot="conversation.chat.node"] table{
1158
+ border-collapse:separate !important;
1159
+ border-spacing:3px !important;
1160
+ width:100% !important;
1161
+ border:none !important;
1162
+ font-size:var(--dsw-font-markdown-base-font-size) !important;
1163
+ }
1164
+ div[data-slot="conversation.chat.node"] table thead th{
1165
+ background:var(--dsw-alias-markdown-inline-code) !important;
1166
+ color:inherit !important;
1167
+ font-weight:400 !important;
1168
+ font-size:inherit !important;
1169
+ padding:7px 10px !important;
1170
+ border:none !important;
1171
+ border-radius:6px !important;
1172
+ }
1173
+ div[data-slot="conversation.chat.node"] table tbody td{
1174
+ background:var(--dsw-alias-markdown-inline-code) !important;
1175
+ color:inherit !important;
1176
+ font-size:inherit !important;
1177
+ padding:7px 10px !important;
1178
+ vertical-align:top !important;
1179
+ border:none !important;
1180
+ border-radius:6px !important;
1181
+ }
1182
+ div[data-slot="conversation.chat.node"] table code,
1183
+ div[data-slot="conversation.chat.node"] table pre{
1184
+ background:transparent !important;
1185
+ border:none !important;
1186
+ box-shadow:none !important;
1187
+ }
939
1188
  `;
940
1189
  function buildRuntimeCss(value) {
941
1190
  const rules = [];
@@ -987,48 +1236,48 @@ function runtimeStyleElement() {
987
1236
  }
988
1237
  return style;
989
1238
  }
990
- const BASE_CSS = `
991
- .dut-settings{display:grid;gap:12px;max-width:680px;padding:6px 2px 36px;color:var(--dsw-alias-label-primary)}
992
- .dut-settings-header{display:flex;align-items:flex-start;gap:12px;padding:6px 2px 2px}
993
- .dut-logo{flex:none;display:grid;place-items:center;width:38px;height:38px;border-radius:11px;border:1px solid var(--dsw-alias-border-l1);background:linear-gradient(135deg,color-mix(in srgb,var(--dsw-alias-state-business-primary) 16%,transparent),transparent);font-size:18px;line-height:1}
994
- .dut-settings-header h2{font-size:19px;letter-spacing:-.01em;margin:2px 0 4px}
995
- .dut-settings-header p{max-width:600px;margin:0;color:var(--dsw-alias-label-secondary);font-size:12.5px;line-height:1.55}
996
- .dut-panel{display:grid;gap:0;border:1px solid var(--dsw-alias-border-l1);border-radius:14px;background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-shadow-lv1);overflow:hidden}
997
- .dut-section-label{font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);padding:14px 16px 6px}
998
- .dut-field{display:grid;gap:8px;padding:8px 16px 14px}
999
- .dut-field+.dut-field{border-top:1px solid var(--dsw-alias-border-l1)}
1000
- .dut-field-top{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
1001
- .dut-field-top>span{font-size:13.5px;font-weight:600}
1002
- .dut-field small{font-size:11.5px;line-height:1.5;color:var(--dsw-alias-label-secondary)}
1003
- .dut-controls{display:flex;align-items:center;gap:8px}
1004
- .dut-stepper{display:inline-flex;align-items:center;border:1px solid var(--dsw-alias-border-l1);border-radius:9px;background:var(--dsw-alias-bg-layer-2);overflow:hidden}
1005
- .dut-stepper button{width:30px;height:32px;border:none;background:transparent;color:inherit;font-size:15px;font-weight:500;line-height:1;cursor:pointer;display:grid;place-items:center;transition:background .15s ease}
1006
- .dut-stepper button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
1007
- .dut-stepper button:disabled{opacity:.35;cursor:default}
1008
- .dut-stepper input{box-sizing:border-box;width:64px;height:32px;border:none;border-left:1px solid var(--dsw-alias-border-l1);border-right:1px solid var(--dsw-alias-border-l1);background:transparent;color:inherit;font:inherit;font-size:13px;text-align:center;-moz-appearance:textfield}
1009
- .dut-stepper input::-webkit-outer-spin-button,.dut-stepper input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
1010
- .dut-stepper input:focus{outline:none}
1011
- .dut-seg{display:inline-flex;padding:3px;gap:3px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-2)}
1012
- .dut-seg button{border:none;border-radius:7px;padding:5px 12px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12.5px;cursor:pointer;transition:background .15s ease,color .15s ease}
1013
- .dut-seg button:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
1014
- .dut-seg button.dut-seg-active{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-weight:600;box-shadow:none}
1015
- .dut-seg button.dut-seg-active:hover:not(:disabled){color:var(--dsw-alias-state-business-primary)}
1016
- .dut-seg button:disabled{opacity:.45;cursor:default}
1017
- /* The selected Settings-section tab — the stock shell paints a barely-there
1018
- grey; brand-tint it so the selection reads clearly (and in the README shot). */
1019
- [role="dialog"] nav button[aria-selected="true"],[role="dialog"] nav button[aria-current="true"]{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-weight:600}
1020
- .dut-presets{display:inline-flex;flex-wrap:wrap;margin-top:2px}
1021
- .dut-btn{display:inline-flex;align-items:center;height:26px;padding:0 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:11.5px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
1022
- .dut-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
1023
- .dut-btn.dut-btn-active{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 45%,transparent);color:var(--dsw-alias-state-business-primary)}
1024
- .dut-btn.dut-btn-active:hover{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 18%,transparent);color:var(--dsw-alias-state-business-primary)}
1025
- .dut-btn:disabled{opacity:.4;cursor:default}
1026
- .dut-status{justify-self:start;font-size:11.5px;padding:3px 10px;border-radius:999px;background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);color:var(--dsw-alias-state-success-primary);animation:dut-fadein .18s ease}
1027
- @keyframes dut-fadein{from{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:none}}
1028
- .dut-loading{padding:24px;border-radius:12px;background:var(--dsw-alias-bg-layer-2);font-size:12px;color:var(--dsw-alias-label-secondary)}
1029
- .dut-alert{padding:10px 12px;border-radius:10px;font-size:12px;line-height:1.5}
1030
- .dut-alert.warning{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 12%,transparent);color:var(--dsw-alias-state-warn-label)}
1031
- .dut-alert.error{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
1239
+ const BASE_CSS = `
1240
+ .dut-settings{display:grid;gap:12px;max-width:680px;padding:6px 2px 36px;color:var(--dsw-alias-label-primary)}
1241
+ .dut-settings-header{display:flex;align-items:flex-start;gap:12px;padding:6px 2px 2px}
1242
+ .dut-logo{flex:none;display:grid;place-items:center;width:38px;height:38px;border-radius:11px;border:1px solid var(--dsw-alias-border-l1);background:linear-gradient(135deg,color-mix(in srgb,var(--dsw-alias-state-business-primary) 16%,transparent),transparent);font-size:18px;line-height:1}
1243
+ .dut-settings-header h2{font-size:19px;letter-spacing:-.01em;margin:2px 0 4px}
1244
+ .dut-settings-header p{max-width:600px;margin:0;color:var(--dsw-alias-label-secondary);font-size:12.5px;line-height:1.55}
1245
+ .dut-panel{display:grid;gap:0;border:1px solid var(--dsw-alias-border-l1);border-radius:14px;background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-shadow-lv1);overflow:hidden}
1246
+ .dut-section-label{font-size:11px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);padding:14px 16px 6px}
1247
+ .dut-field{display:grid;gap:8px;padding:8px 16px 14px}
1248
+ .dut-field+.dut-field{border-top:1px solid var(--dsw-alias-border-l1)}
1249
+ .dut-field-top{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap}
1250
+ .dut-field-top>span{font-size:13.5px;font-weight:600}
1251
+ .dut-field small{font-size:11.5px;line-height:1.5;color:var(--dsw-alias-label-secondary)}
1252
+ .dut-controls{display:flex;align-items:center;gap:8px}
1253
+ .dut-stepper{display:inline-flex;align-items:center;border:1px solid var(--dsw-alias-border-l1);border-radius:9px;background:var(--dsw-alias-bg-layer-2);overflow:hidden}
1254
+ .dut-stepper button{width:30px;height:32px;border:none;background:transparent;color:inherit;font-size:15px;font-weight:500;line-height:1;cursor:pointer;display:grid;place-items:center;transition:background .15s ease}
1255
+ .dut-stepper button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
1256
+ .dut-stepper button:disabled{opacity:.35;cursor:default}
1257
+ .dut-stepper input{box-sizing:border-box;width:64px;height:32px;border:none;border-left:1px solid var(--dsw-alias-border-l1);border-right:1px solid var(--dsw-alias-border-l1);background:transparent;color:inherit;font:inherit;font-size:13px;text-align:center;-moz-appearance:textfield}
1258
+ .dut-stepper input::-webkit-outer-spin-button,.dut-stepper input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
1259
+ .dut-stepper input:focus{outline:none}
1260
+ .dut-seg{display:inline-flex;padding:3px;gap:3px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-2)}
1261
+ .dut-seg button{border:none;border-radius:7px;padding:5px 12px;background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:12.5px;cursor:pointer;transition:background .15s ease,color .15s ease}
1262
+ .dut-seg button:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
1263
+ .dut-seg button.dut-seg-active{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-weight:600;box-shadow:none}
1264
+ .dut-seg button.dut-seg-active:hover:not(:disabled){color:var(--dsw-alias-state-business-primary)}
1265
+ .dut-seg button:disabled{opacity:.45;cursor:default}
1266
+ /* The selected Settings-section tab — the stock shell paints a barely-there
1267
+ grey; brand-tint it so the selection reads clearly (and in the README shot). */
1268
+ [role="dialog"] nav button[aria-selected="true"],[role="dialog"] nav button[aria-current="true"]{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-weight:600}
1269
+ .dut-presets{display:inline-flex;flex-wrap:wrap;margin-top:2px}
1270
+ .dut-btn{display:inline-flex;align-items:center;height:26px;padding:0 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:transparent;color:var(--dsw-alias-label-secondary);font:inherit;font-size:11.5px;cursor:pointer;transition:background .15s ease,color .15s ease,border-color .15s ease}
1271
+ .dut-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}
1272
+ .dut-btn.dut-btn-active{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 45%,transparent);color:var(--dsw-alias-state-business-primary)}
1273
+ .dut-btn.dut-btn-active:hover{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 18%,transparent);color:var(--dsw-alias-state-business-primary)}
1274
+ .dut-btn:disabled{opacity:.4;cursor:default}
1275
+ .dut-status{justify-self:start;font-size:11.5px;padding:3px 10px;border-radius:999px;background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);color:var(--dsw-alias-state-success-primary);animation:dut-fadein .18s ease}
1276
+ @keyframes dut-fadein{from{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:none}}
1277
+ .dut-loading{padding:24px;border-radius:12px;background:var(--dsw-alias-bg-layer-2);font-size:12px;color:var(--dsw-alias-label-secondary)}
1278
+ .dut-alert{padding:10px 12px;border-radius:10px;font-size:12px;line-height:1.5}
1279
+ .dut-alert.warning{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 12%,transparent);color:var(--dsw-alias-state-warn-label)}
1280
+ .dut-alert.error{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}
1032
1281
  `;
1033
1282
  function installBaseStyles() {
1034
1283
  const id = 'dsh-ui-tweaks-base';
@@ -1226,7 +1475,7 @@ function apply(ctx) {
1226
1475
  id: 'gitbar',
1227
1476
  order: 30,
1228
1477
  locale: NS,
1229
- inject: () => ({ controller }),
1478
+ inject: () => ({ controller, sessionsService: ctx.sessions }),
1230
1479
  }, gitbar_tsx_1.GitBar));
1231
1480
  }
1232
1481
  };