@civilization/dsh-experimental-git 0.0.0-stage → 0.2.1-rc.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 ADDED
@@ -0,0 +1,2836 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@civilization/dsh-experimental-git",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react_jsx_runtime = require("react/jsx-runtime");
8
+ let react = require("react");
9
+ let react_dom = require("react-dom");
10
+ let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
11
+ /** Implementation identity in the tab system */
12
+ const GIT_ID = "@deepseek-ai/dsh-experimental-git";
13
+ /** Git artwork for the Sidebar Guide */
14
+ function GuideArtworkGit() {
15
+ return (0, react_jsx_runtime.jsxs)("svg", {
16
+ width: "40",
17
+ height: "40",
18
+ viewBox: "0 0 36 36",
19
+ fill: "none",
20
+ xmlns: "http://www.w3.org/2000/svg",
21
+ children: [
22
+ (0, react_jsx_runtime.jsx)("line", {
23
+ x1: "12",
24
+ y1: "9",
25
+ x2: "12",
26
+ y2: "27",
27
+ stroke: "#F05133",
28
+ strokeWidth: "2.5",
29
+ strokeLinecap: "round"
30
+ }),
31
+ (0, react_jsx_runtime.jsx)("path", {
32
+ d: "M12 21C12 18 15 15 18 15H22C23.5 15 24 14.5 24 13V12",
33
+ stroke: "#F05133",
34
+ strokeWidth: "2.5",
35
+ strokeLinecap: "round",
36
+ fill: "none"
37
+ }),
38
+ (0, react_jsx_runtime.jsx)("circle", {
39
+ cx: "12",
40
+ cy: "26",
41
+ r: "3.5",
42
+ fill: "#FFFFFF",
43
+ stroke: "#F05133",
44
+ strokeWidth: "2.5"
45
+ }),
46
+ (0, react_jsx_runtime.jsx)("circle", {
47
+ cx: "12",
48
+ cy: "10",
49
+ r: "3.5",
50
+ fill: "#FFFFFF",
51
+ stroke: "#F05133",
52
+ strokeWidth: "2.5"
53
+ }),
54
+ (0, react_jsx_runtime.jsx)("circle", {
55
+ cx: "24",
56
+ cy: "11",
57
+ r: "3.5",
58
+ fill: "#FFFFFF",
59
+ stroke: "#3680F6",
60
+ strokeWidth: "2.5"
61
+ })
62
+ ]
63
+ });
64
+ }
65
+ /**
66
+ * Tab definition for the Git right-sidebar viewer.
67
+ * @param t - namespace-bound translation function.
68
+ * @returns Complete sidebar tab definition.
69
+ */
70
+ function gitDefinition(t) {
71
+ return {
72
+ id: GIT_ID,
73
+ kind: "git",
74
+ priority: "builtin",
75
+ title: () => t("type.label"),
76
+ guide: [{
77
+ id: "git",
78
+ commandId: "workspace.git",
79
+ order: 15,
80
+ title: () => t("guide.title"),
81
+ description: () => t("guide.description"),
82
+ icon: GuideArtworkGit
83
+ }]
84
+ };
85
+ }
86
+ //#endregion
87
+ //#region lib/types/client/git-helpers.js
88
+ /**
89
+ * Conventional Commits and presentation helpers for Git commits and avatars.
90
+ */
91
+ /**
92
+ * Parse conventional commit prefix from a commit subject.
93
+ * @param subject - Raw first line of commit message.
94
+ * @returns Parsed type, scope, and clean subject.
95
+ */
96
+ function parseConventionalCommit(subject) {
97
+ const trimmed = subject.trim();
98
+ if (/^merge\s+(pull\s+request|branch|remote-tracking\s+branch)/i.test(trimmed)) return {
99
+ type: "merge",
100
+ cleanSubject: trimmed
101
+ };
102
+ const match = /^(feat|fix|style|refactor|docs|test|chore|release|revert)(?:\(([^)]+)\))?!?:\s*(.*)$/i.exec(trimmed);
103
+ if (match && match[1]) {
104
+ const rawType = match[1].toLowerCase();
105
+ const scope = match[2]?.trim();
106
+ return {
107
+ type: rawType,
108
+ ...scope !== void 0 ? { scope } : {},
109
+ cleanSubject: trimmed
110
+ };
111
+ }
112
+ return { cleanSubject: trimmed };
113
+ }
114
+ const AVATAR_PALETTE = [
115
+ "#388bfd",
116
+ "#2ea043",
117
+ "#f0883e",
118
+ "#a371f7",
119
+ "#db61a2",
120
+ "#39c5bb",
121
+ "#f9c513",
122
+ "#6f42c1"
123
+ ];
124
+ /**
125
+ * Deterministically compute avatar initial and background color for an author name.
126
+ * @param author - Author name or email.
127
+ * @returns Initial letter and hex color code.
128
+ */
129
+ function getAuthorAvatar(author) {
130
+ const clean = author.trim();
131
+ const initial = clean.length > 0 ? clean[0]?.toUpperCase() ?? "?" : "?";
132
+ let hash = 0;
133
+ for (let i = 0; i < clean.length; i++) {
134
+ hash = (hash << 5) - hash + clean.charCodeAt(i);
135
+ hash |= 0;
136
+ }
137
+ return {
138
+ initial,
139
+ color: AVATAR_PALETTE[Math.abs(hash) % AVATAR_PALETTE.length] ?? "#388bfd"
140
+ };
141
+ }
142
+ /**
143
+ * Format date string into YYYY-MM-DD HH:mm:ss.
144
+ * @param dateStr - ISO or Git date string.
145
+ * @returns Clean formatted local date and time string.
146
+ */
147
+ function formatFullDate(dateStr) {
148
+ const d = new Date(dateStr);
149
+ if (Number.isNaN(d.getTime())) return dateStr;
150
+ const pad = (n) => String(n).padStart(2, "0");
151
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
152
+ }
153
+ const GRAPH_LANE_PALETTE = [
154
+ "#388bfd",
155
+ "#3fb950",
156
+ "#f0883e",
157
+ "#a371f7",
158
+ "#58a6ff",
159
+ "#bc8cff",
160
+ "#db61a2",
161
+ "#2ea043"
162
+ ];
163
+ const ROW_HEIGHT = 28;
164
+ const LANE_WIDTH = 16;
165
+ const LANE_X_OFFSET = 10;
166
+ /**
167
+ * Compute global continuous SVG DAG topology graph for commit items (IntelliJ IDEA grade).
168
+ * Eliminates per-row segmentation gaps, floating nodes, and misaligned curves.
169
+ * @param commits - Ordered commit items.
170
+ * @returns Fully computed nodes, edges, maxLane, and width.
171
+ */
172
+ function computeDagGraph(commits) {
173
+ if (commits.length === 0) return {
174
+ nodes: [],
175
+ edges: [],
176
+ maxLane: 0,
177
+ graphWidth: 36
178
+ };
179
+ const hashToIndex = /* @__PURE__ */ new Map();
180
+ commits.forEach((c, idx) => hashToIndex.set(c.hash, idx));
181
+ const mainlineSet = /* @__PURE__ */ new Set();
182
+ let curr = commits.find((c) => c.refs?.some((r) => r.includes("HEAD") || r === "master" || r === "main"))?.hash ?? commits[0]?.hash;
183
+ while (curr && hashToIndex.has(curr)) {
184
+ mainlineSet.add(curr);
185
+ const commitIdx = hashToIndex.get(curr);
186
+ if (commitIdx === void 0) break;
187
+ const c = commits[commitIdx];
188
+ if (!c || !c.parents || c.parents.length === 0) break;
189
+ curr = c.parents[0];
190
+ }
191
+ const activeLanes = [null];
192
+ const commitLanes = Array.from({ length: commits.length }, () => 0);
193
+ commits.forEach((c, idx) => {
194
+ let lane = 0;
195
+ if (mainlineSet.has(c.hash)) {
196
+ lane = 0;
197
+ for (let l = 1; l < activeLanes.length; l++) if (activeLanes[l] === c.hash) activeLanes[l] = null;
198
+ } else {
199
+ let foundLane = -1;
200
+ for (let l = 1; l < activeLanes.length; l++) if (activeLanes[l] === c.hash) {
201
+ foundLane = l;
202
+ break;
203
+ }
204
+ if (foundLane !== -1) {
205
+ lane = foundLane;
206
+ activeLanes[lane] = null;
207
+ } else {
208
+ let slot = -1;
209
+ for (let l = 1; l < activeLanes.length; l++) if (activeLanes[l] === null) {
210
+ slot = l;
211
+ break;
212
+ }
213
+ if (slot !== -1) lane = slot;
214
+ else {
215
+ lane = Math.max(1, activeLanes.length);
216
+ while (activeLanes.length <= lane) activeLanes.push(null);
217
+ }
218
+ }
219
+ }
220
+ commitLanes[idx] = lane;
221
+ if (c.parents && c.parents.length > 0) c.parents.forEach((parentHash, pIdx) => {
222
+ if (mainlineSet.has(parentHash)) return;
223
+ if (activeLanes.includes(parentHash)) return;
224
+ if (pIdx === 0 && lane >= 1 && activeLanes[lane] === null) activeLanes[lane] = parentHash;
225
+ else {
226
+ let slot = -1;
227
+ for (let l = 1; l < activeLanes.length; l++) if (activeLanes[l] === null) {
228
+ slot = l;
229
+ break;
230
+ }
231
+ if (slot !== -1) activeLanes[slot] = parentHash;
232
+ else activeLanes.push(parentHash);
233
+ }
234
+ });
235
+ while (activeLanes.length > 1 && activeLanes.at(-1) === null) activeLanes.pop();
236
+ });
237
+ const maxLane = Math.max(0, ...commitLanes);
238
+ const edges = [];
239
+ const processedEdges = /* @__PURE__ */ new Set();
240
+ commits.forEach((c, idx) => {
241
+ const fromLane = commitLanes[idx] ?? 0;
242
+ const x1 = fromLane * LANE_WIDTH + LANE_X_OFFSET;
243
+ const y1 = idx * ROW_HEIGHT + ROW_HEIGHT / 2;
244
+ const nodeColor = GRAPH_LANE_PALETTE[fromLane % GRAPH_LANE_PALETTE.length] ?? "#388bfd";
245
+ if (!c.parents || c.parents.length === 0) return;
246
+ c.parents.forEach((pHash) => {
247
+ const edgeKey = `${c.hash}->${pHash}`;
248
+ if (processedEdges.has(edgeKey)) return;
249
+ processedEdges.add(edgeKey);
250
+ const pIdxInList = hashToIndex.get(pHash);
251
+ if (pIdxInList !== void 0) {
252
+ const toLane = commitLanes[pIdxInList] ?? 0;
253
+ const x2 = toLane * LANE_WIDTH + LANE_X_OFFSET;
254
+ const y2 = pIdxInList * ROW_HEIGHT + ROW_HEIGHT / 2;
255
+ const edgeColor = fromLane > 0 ? nodeColor : toLane > 0 ? GRAPH_LANE_PALETTE[toLane % GRAPH_LANE_PALETTE.length] ?? nodeColor : nodeColor;
256
+ if (x1 === x2) edges.push({
257
+ key: edgeKey,
258
+ fromHash: c.hash,
259
+ toHash: pHash,
260
+ color: edgeColor,
261
+ d: `M ${x1} ${y1} L ${x2} ${y2}`
262
+ });
263
+ else if (pIdxInList === idx + 1) edges.push({
264
+ key: edgeKey,
265
+ fromHash: c.hash,
266
+ toHash: pHash,
267
+ color: edgeColor,
268
+ d: `M ${x1} ${y1} C ${x1} ${y1 + 14}, ${x2} ${y2 - 14}, ${x2} ${y2}`
269
+ });
270
+ else if (toLane === 0) edges.push({
271
+ key: edgeKey,
272
+ fromHash: c.hash,
273
+ toHash: pHash,
274
+ color: edgeColor,
275
+ d: `M ${x1} ${y1} L ${x1} ${y2 - 28} C ${x1} ${y2 - 14}, ${x2} ${y2 - 14}, ${x2} ${y2}`
276
+ });
277
+ else edges.push({
278
+ key: edgeKey,
279
+ fromHash: c.hash,
280
+ toHash: pHash,
281
+ color: edgeColor,
282
+ d: `M ${x1} ${y1} C ${x1} ${y1 + 14}, ${x2} ${y1 + 14}, ${x2} ${y1 + 28} L ${x2} ${y2}`
283
+ });
284
+ } else {
285
+ const bottomY = commits.length * ROW_HEIGHT;
286
+ edges.push({
287
+ key: edgeKey,
288
+ fromHash: c.hash,
289
+ color: nodeColor,
290
+ d: `M ${x1} ${y1} L ${x1} ${bottomY}`
291
+ });
292
+ }
293
+ });
294
+ });
295
+ return {
296
+ nodes: commits.map((c, idx) => {
297
+ const lane = commitLanes[idx] ?? 0;
298
+ const x = lane * LANE_WIDTH + LANE_X_OFFSET;
299
+ const y = idx * ROW_HEIGHT + ROW_HEIGHT / 2;
300
+ const color = GRAPH_LANE_PALETTE[lane % GRAPH_LANE_PALETTE.length] ?? "#388bfd";
301
+ const isHead = Boolean(c.refs?.some((r) => r.includes("HEAD") || r === "master" || r === "main"));
302
+ const hasTag = Boolean(c.refs?.some((r) => r.startsWith("tag: ") || r.includes("tag:")));
303
+ return {
304
+ hash: c.hash,
305
+ lane,
306
+ color,
307
+ x,
308
+ y,
309
+ isHead,
310
+ hasTag
311
+ };
312
+ }),
313
+ edges,
314
+ maxLane,
315
+ graphWidth: Math.max(36, (maxLane + 1) * LANE_WIDTH + 16)
316
+ };
317
+ }
318
+ //#endregion
319
+ //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/experimental/git/src/client/GitBody.module.css.mjs
320
+ const css$1 = ".n1ttEW_root{height:100%;min-height:0;color:var(--dsw-alias-label-primary);font-size:var(--dsh-content-font-size-secondary,13px);user-select:none;background:0 0;flex-direction:column;flex:auto;line-height:1.5;display:flex}.n1ttEW_header{box-sizing:border-box;border-bottom:.5px solid var(--dsw-alias-border-l2);flex:none;justify-content:space-between;align-items:center;gap:8px;height:38px;padding:0 10px 0 12px;display:flex}.n1ttEW_branchInfo{align-items:center;gap:6px;min-width:0;display:flex}.n1ttEW_branchBadge{border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;align-items:center;gap:4px;max-width:160px;padding:2px 7px;font-size:12px;font-weight:500;display:inline-flex;overflow:hidden}.n1ttEW_branchIcon{color:var(--dsw-alias-state-business-primary);flex-shrink:0}.n1ttEW_statusAheadBehind{gap:4px;font-size:11px;font-weight:600;display:inline-flex}.n1ttEW_aheadText{color:var(--dsw-alias-state-business-primary)}.n1ttEW_behindText{color:var(--dsw-alias-state-warn-primary)}.n1ttEW_headerActions{align-items:center;gap:4px;display:flex}.n1ttEW_iconButton{border-radius:var(--dsw-radius-sm);width:26px;height:26px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;justify-content:center;align-items:center;padding:0;transition:background-color .15s,color .15s;display:inline-flex}.n1ttEW_iconButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.n1ttEW_iconButton.n1ttEW_spinning svg{animation:.8s linear infinite n1ttEW_spin}@keyframes n1ttEW_spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.n1ttEW_tabs{border-bottom:.5px solid var(--dsw-alias-border-l2);background:0 0;align-items:center;gap:4px;padding:4px 10px;display:flex}.n1ttEW_tab{border-radius:var(--dsw-radius-sm);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;align-items:center;gap:5px;padding:4px 10px;font-size:12px;font-weight:500;transition:all .15s;display:inline-flex}.n1ttEW_tab:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.n1ttEW_tabActive{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-state-business-primary);font-weight:600}.n1ttEW_tabCount{background:var(--dsw-alias-interactive-bg-hover);color:inherit;border-radius:10px;justify-content:center;align-items:center;padding:0 5px;font-size:10px;font-weight:700;display:inline-flex}.n1ttEW_content{flex-direction:column;flex:auto;gap:10px;min-height:0;padding:8px 10px;display:flex;overflow-y:auto}.n1ttEW_emptyState{text-align:center;color:var(--dsw-alias-label-tertiary);flex-direction:column;justify-content:center;align-items:center;gap:8px;padding:32px 16px;display:flex}.n1ttEW_emptyState svg{opacity:.6;width:28px;height:28px}.n1ttEW_section{border-radius:var(--dsw-radius-md);border:.5px solid var(--dsw-alias-border-l2);background:0 0;flex-direction:column;display:flex;overflow:hidden}.n1ttEW_sectionHeader{border-bottom:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);cursor:pointer;color:var(--dsw-alias-label-primary);justify-content:space-between;align-items:center;padding:6px 10px;font-size:12px;font-weight:600;display:flex}.n1ttEW_sectionTitle{align-items:center;gap:6px;display:flex}.n1ttEW_sectionActions{align-items:center;gap:4px;display:flex}.n1ttEW_actionTextBtn{border-radius:var(--dsw-radius-xs,3px);border:.5px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;padding:2px 6px;font-size:11px;transition:all .12s}.n1ttEW_actionTextBtn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.n1ttEW_fileList{flex-direction:column;display:flex}.n1ttEW_fileItem{border-top:.5px solid var(--dsw-alias-border-l1);cursor:pointer;color:var(--dsw-alias-label-primary);justify-content:space-between;align-items:center;padding:5px 10px;font-size:12px;transition:background .12s;display:flex}.n1ttEW_fileItem:hover{background:var(--dsw-alias-interactive-bg-hover)}.n1ttEW_fileLeft{flex:1;align-items:center;gap:6px;min-width:0;display:flex}.n1ttEW_statusBadge{border-radius:3px;flex-shrink:0;justify-content:center;align-items:center;width:16px;height:16px;font-size:10px;font-weight:700;display:inline-flex}.n1ttEW_statusM{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 15%, transparent);color:var(--dsw-alias-state-business-primary)}.n1ttEW_statusA{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 15%, transparent);color:var(--dsw-alias-state-success-primary)}.n1ttEW_statusD{background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 15%, transparent);color:var(--dsw-alias-state-error-primary)}.n1ttEW_statusU{background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 15%, transparent);color:var(--dsw-alias-state-warn-primary)}.n1ttEW_fileName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.n1ttEW_fileDir{color:var(--dsw-alias-label-tertiary);font-size:11px}.n1ttEW_fileItemActions{opacity:0;align-items:center;gap:4px;transition:opacity .12s;display:flex}.n1ttEW_fileItem:hover .n1ttEW_fileItemActions{opacity:1}.n1ttEW_fileMiniBtn{border-radius:var(--dsw-radius-xs,3px);background:var(--dsw-alias-interactive-bg-hover);width:20px;height:20px;color:var(--dsw-alias-label-secondary);cursor:pointer;border:none;justify-content:center;align-items:center;font-size:12px;transition:background .12s,color .12s;display:inline-flex}.n1ttEW_fileMiniBtn:hover{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary)}.n1ttEW_commitBox{border-radius:var(--dsw-radius-md);border:.5px solid var(--dsw-alias-border-l2);background:0 0;flex-direction:column;gap:8px;margin-top:4px;padding:10px;display:flex}.n1ttEW_commitTextarea{box-sizing:border-box;border-radius:var(--dsw-radius-sm);border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover);width:100%;min-height:54px;max-height:120px;color:var(--dsw-alias-label-primary);resize:vertical;outline:none;padding:6px 8px;font-family:inherit;font-size:12px}.n1ttEW_commitTextarea:focus{border-color:var(--dsw-alias-state-business-primary)}.n1ttEW_commitButtonRow{justify-content:flex-end;align-items:center;gap:6px;display:flex}.n1ttEW_commitBtn{border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-label-primary-inverted);cursor:pointer;border:none;align-items:center;gap:4px;padding:4px 12px;font-size:12px;font-weight:600;transition:background .15s;display:inline-flex}.n1ttEW_commitBtn:hover{background:var(--dsw-alias-state-success-secondary)}.n1ttEW_commitPushBtn{border-radius:var(--dsw-radius-sm);border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:4px;padding:4px 12px;font-size:12px;font-weight:500;transition:all .15s;display:inline-flex}.n1ttEW_commitPushBtn:hover{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary)}.n1ttEW_treeContainer{flex-direction:column;gap:0;min-height:0;display:flex;position:relative}.n1ttEW_treeRow{border-radius:var(--dsw-radius-sm);cursor:pointer;height:28px;color:var(--dsw-alias-label-primary);user-select:none;align-items:center;padding:0 6px;font-size:12px;transition:background .12s;display:flex}.n1ttEW_treeRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.n1ttEW_treeRowSelected{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-active)!important}.n1ttEW_graphSvg{flex-shrink:0;height:28px;margin-right:6px}.n1ttEW_graphOverlaySvg{pointer-events:none;z-index:1;position:absolute;top:0;left:10px}.n1ttEW_treeBody{flex:1;align-items:center;gap:6px;min-width:0;display:flex}.n1ttEW_refBadge{white-space:nowrap;border-radius:10px;flex-shrink:0;align-items:center;padding:1px 5px;font-size:10px;font-weight:700;line-height:12px;display:inline-flex}.n1ttEW_refHead{background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 18%, transparent);color:var(--dsw-alias-state-warn-primary);border:.5px solid var(--dsw-alias-state-warn-primary)}.n1ttEW_refBranch{background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 18%, transparent);color:var(--dsw-alias-state-success-primary);border:.5px solid var(--dsw-alias-state-success-primary)}.n1ttEW_refRemote{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent);color:var(--dsw-alias-state-business-primary);border:.5px solid var(--dsw-alias-state-business-primary)}.n1ttEW_treeSubject{text-overflow:ellipsis;white-space:nowrap;flex:1;font-weight:500;overflow:hidden}.n1ttEW_treeAuthor{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;flex-shrink:0;max-width:80px;font-size:11px;overflow:hidden}.n1ttEW_treeTime{color:var(--dsw-alias-label-tertiary);white-space:nowrap;flex-shrink:0;font-size:11px}.n1ttEW_treeHash{color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover);border-radius:var(--dsw-radius-xs,3px);flex-shrink:0;padding:0 4px;font-family:monospace;font-size:11px}.n1ttEW_commitDetailPanel{border-radius:var(--dsw-radius-lg);border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-menu);backdrop-filter:var(--dsw-menu-backdrop-filter);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);flex-direction:column;gap:8px;margin-top:8px;padding:12px;display:flex}.n1ttEW_detailHeader{border-bottom:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:4px;padding-bottom:8px;display:flex}.n1ttEW_detailSubject{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600}.n1ttEW_detailMetaRow{color:var(--dsw-alias-label-tertiary);justify-content:space-between;align-items:center;font-size:11px;display:flex}.n1ttEW_detailFilesList{flex-direction:column;gap:2px;max-height:180px;display:flex;overflow-y:auto}.n1ttEW_detailFileItem{border-radius:var(--dsw-radius-sm);cursor:pointer;color:var(--dsw-alias-label-primary);justify-content:space-between;align-items:center;padding:4px 6px;font-size:11px;transition:background .12s;display:flex}.n1ttEW_detailFileItem:hover{background:var(--dsw-alias-interactive-bg-hover)}.n1ttEW_numstat{gap:4px;font-family:monospace;font-size:10px;display:inline-flex}.n1ttEW_addStat{color:var(--dsw-alias-state-success-primary)}.n1ttEW_delStat{color:var(--dsw-alias-state-error-primary)}.n1ttEW_diffViewer{border-radius:var(--dsw-radius-md);background:var(--dsw-alias-markdown-code-block);border:.5px solid var(--dsw-alias-border-l2);max-height:260px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:6px;padding:8px;font-family:monospace;font-size:11px;display:flex;overflow:auto}.n1ttEW_diffLine{white-space:pre-wrap;word-break:break-all;line-height:16px}.n1ttEW_diffAdd{background:var(--dsw-alias-code-diff-added);color:var(--dsw-alias-state-success-primary)}.n1ttEW_diffDel{background:var(--dsw-alias-code-diff-deleted);color:var(--dsw-alias-state-error-primary)}.n1ttEW_diffHunk{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent);color:var(--dsw-alias-state-business-primary);font-weight:600}.n1ttEW_refTag{color:#f0883e;background:#f0883e2e;border:.5px solid #f0883e}.n1ttEW_treeRowHighlighted{border-left:2px solid var(--dsw-alias-state-business-primary);animation:2.5s ease-out forwards n1ttEW_rowGlow}@keyframes n1ttEW_rowGlow{0%{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 35%, transparent);box-shadow:inset 0 0 12px color-mix(in srgb, var(--dsw-alias-state-business-primary) 40%, transparent)}40%{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 25%, transparent);box-shadow:inset 0 0 8px color-mix(in srgb, var(--dsw-alias-state-business-primary) 20%, transparent)}to{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent);box-shadow:none}}.n1ttEW_locateGlowRing{transform-origin:50%;stroke:var(--dsw-alias-state-business-primary);stroke-width:2px;fill:none;animation:1.5s ease-in-out infinite n1ttEW_pulseRing}@keyframes n1ttEW_pulseRing{0%{r:6;opacity:1}50%{r:10;opacity:.4}to{r:12;opacity:0}}.n1ttEW_treeRowActions{opacity:0;align-items:center;gap:2px;margin-left:4px;transition:opacity .12s;display:flex}.n1ttEW_treeRow:hover .n1ttEW_treeRowActions{opacity:1}.n1ttEW_treeActionBtn{border-radius:var(--dsw-radius-xs,3px);background:var(--dsw-alias-interactive-bg-hover);height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;border:none;justify-content:center;align-items:center;padding:1px 4px;font-size:10px;transition:background .12s,color .12s;display:inline-flex}.n1ttEW_treeActionBtn:hover{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary)}.n1ttEW_tagList{flex-direction:column;gap:6px;display:flex}.n1ttEW_tagCard{border-radius:var(--dsw-radius-md);border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover);flex-direction:column;gap:6px;padding:10px 12px;transition:border-color .15s,background .15s;display:flex}.n1ttEW_tagCard:hover{border-color:var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-active)}.n1ttEW_tagCardHeader{justify-content:space-between;align-items:center;gap:8px;display:flex}.n1ttEW_tagTitleRow{flex:1;align-items:center;gap:8px;min-width:0;display:flex}.n1ttEW_tagName{color:var(--dsw-alias-state-business-primary);cursor:pointer;text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:600;overflow:hidden}.n1ttEW_tagName:hover{text-decoration:underline}.n1ttEW_tagShaPill{border-radius:var(--dsw-radius-xs,3px);background:color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);color:var(--dsw-alias-label-secondary);cursor:pointer;padding:1px 6px;font-family:monospace;font-size:11px}.n1ttEW_tagShaPill:hover{background:color-mix(in srgb, var(--dsw-alias-label-primary) 15%, transparent);color:var(--dsw-alias-label-primary)}.n1ttEW_tagAnnotatedBadge{color:#f0883e;background:#f0883e2e;border:.5px solid #f0883e;border-radius:8px;padding:1px 5px;font-size:10px;font-weight:600}.n1ttEW_tagActions{flex-shrink:0;align-items:center;gap:4px;display:flex}.n1ttEW_tagLocateBtn{border:.5px solid color-mix(in srgb, var(--dsw-alias-state-business-primary) 40%, transparent);border-radius:var(--dsw-radius-sm);background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 12%, transparent);color:var(--dsw-alias-state-business-primary);cursor:pointer;align-items:center;gap:4px;padding:3px 8px;font-size:11px;font-weight:600;transition:all .15s;display:inline-flex}.n1ttEW_tagLocateBtn:hover{background:var(--dsw-alias-state-business-primary);color:#fff}.n1ttEW_tagMessage{color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.n1ttEW_tagMetaFooter{color:var(--dsw-alias-label-tertiary);justify-content:space-between;align-items:center;margin-top:2px;font-size:11px;display:flex}.n1ttEW_tagAuthor{color:var(--dsw-alias-label-secondary);align-items:center;gap:4px;display:inline-flex}.n1ttEW_tagForm{border-radius:var(--dsw-radius-md);border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);flex-direction:column;gap:8px;padding:12px;display:flex}.n1ttEW_tagFormTitle{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:600}.n1ttEW_tagFormActions{justify-content:flex-end;gap:6px;display:flex}.n1ttEW_treeFilterRow{border-bottom:.5px solid var(--dsw-alias-border-l2);background:0 0;flex-shrink:0;justify-content:space-between;align-items:center;gap:8px;padding:6px 12px;display:flex}.n1ttEW_treeSearchInput{border-radius:var(--dsw-radius-sm);border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-interactive-bg-hover);min-width:0;height:26px;color:var(--dsw-alias-label-primary);outline:none;flex:1;padding:0 8px;font-size:11px;transition:border-color .15s}.n1ttEW_treeSearchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.n1ttEW_mainlineToggleGroup{border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-interactive-bg-hover);border:.5px solid var(--dsw-alias-border-l2);flex-shrink:0;align-items:center;padding:1px;display:inline-flex}.n1ttEW_mainlineToggleBtn{border-radius:var(--dsw-radius-xs,3px);color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:2px 8px;font-size:11px;font-weight:500;transition:all .12s}.n1ttEW_mainlineToggleBtnActive{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary);font-weight:600}.n1ttEW_workstationLayout{flex:auto;min-height:0;display:flex;overflow:hidden;container-type:inline-size}.n1ttEW_tablePane{flex-direction:column;flex:auto;min-width:0;min-height:0;display:flex;overflow-y:auto}.n1ttEW_treeTableHeader{grid-template-columns:var(--git-graph-col-width,48px) minmax(200px, 1fr) 115px 90px 72px;border-bottom:.5px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-label-primary) 3%, transparent);height:28px;color:var(--dsw-alias-label-tertiary);user-select:none;z-index:2;align-items:center;gap:8px;padding:0 10px;font-size:11px;font-weight:600;display:grid;position:sticky;top:0}.n1ttEW_colHeaderTitle{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.n1ttEW_treeRowGrid{box-sizing:border-box;grid-template-columns:var(--git-graph-col-width,48px) minmax(200px, 1fr) 115px 90px 72px;border-bottom:.5px solid color-mix(in srgb, var(--dsw-alias-border-l2) 40%, transparent);height:28px;min-height:28px;max-height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;user-select:none;align-items:center;gap:8px;padding:0 10px;font-size:12px;transition:background .1s;display:grid}.n1ttEW_treeRowGrid:hover{background:var(--dsw-alias-interactive-bg-hover)}.n1ttEW_treeRowGridSelected{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-active)!important}.n1ttEW_subjectCol{align-items:center;gap:6px;min-width:0;display:flex;overflow:hidden}.n1ttEW_typeBadge{border-radius:var(--dsw-radius-xs,3px);text-transform:lowercase;flex-shrink:0;justify-content:center;align-items:center;height:16px;padding:0 5px;font-size:10px;font-weight:600;line-height:16px;display:inline-flex}.n1ttEW_typeFeat{color:#2ea043;background:#2ea04329;border:.5px solid #2ea04366}.n1ttEW_typeFix{color:#f85149;background:#f8514929;border:.5px solid #f8514966}.n1ttEW_typeStyle,.n1ttEW_typeRefactor{color:#8250df;background:#8250df29;border:.5px solid #8250df66}.n1ttEW_typeRelease{color:#388bfd;background:#388bfd29;border:.5px solid #388bfd66}.n1ttEW_typeMerge{color:#6f42c1;background:#6f42c129;border:.5px solid #6f42c166}.n1ttEW_typeTest{color:#d29922;background:#d2992229;border:.5px solid #d2992266}.n1ttEW_typeDocs{color:#39c5bb;background:#39c5bb29;border:.5px solid #39c5bb66}.n1ttEW_typeChore,.n1ttEW_typeRevert{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent);color:var(--dsw-alias-label-secondary);border:.5px solid color-mix(in srgb, var(--dsw-alias-label-secondary) 30%, transparent)}.n1ttEW_authorCol{align-items:center;gap:6px;min-width:0;display:flex;overflow:hidden}.n1ttEW_authorAvatar{color:#fff;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:16px;height:16px;font-size:9px;font-weight:700;display:inline-flex}.n1ttEW_authorNameText{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.n1ttEW_timeCol{color:var(--dsw-alias-label-tertiary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.n1ttEW_shaCol{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-family:monospace;font-size:11px}.n1ttEW_detailsPane{border-left:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-menu);width:330px;backdrop-filter:var(--dsw-menu-backdrop-filter);box-sizing:border-box;flex-direction:column;flex-shrink:0;display:flex;overflow-y:auto}.n1ttEW_detailsHeader{border-bottom:.5px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);letter-spacing:.5px;justify-content:space-between;align-items:center;padding:10px 12px;font-size:11px;font-weight:700;display:flex}.n1ttEW_detailsContent{flex-direction:column;gap:12px;padding:12px;display:flex}.n1ttEW_detailsSubject{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:600;line-height:18px}.n1ttEW_detailsBody{color:var(--dsw-alias-label-secondary);white-space:pre-wrap;word-break:break-word;font-size:11px;line-height:16px}.n1ttEW_detailsSectionTitle{color:var(--dsw-alias-label-tertiary);letter-spacing:.5px;margin-bottom:4px;font-size:10px;font-weight:700}.n1ttEW_detailsMetaGrid{flex-direction:column;gap:6px;font-size:11px;display:flex}.n1ttEW_detailsMetaRow{justify-content:space-between;align-items:center;gap:8px;display:flex}.n1ttEW_detailsMetaLabel{color:var(--dsw-alias-label-tertiary);flex-shrink:0}.n1ttEW_detailsMetaVal{color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;font-family:monospace;overflow:hidden}.n1ttEW_detailsParentLink{color:var(--dsw-alias-state-business-primary);cursor:pointer;font-family:monospace}.n1ttEW_detailsParentLink:hover{text-decoration:underline}.n1ttEW_detailsBottomActions{gap:8px;margin-top:8px;display:flex}.n1ttEW_treeStatusFooter{border-top:.5px solid var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-label-primary) 2%, transparent);height:26px;color:var(--dsw-alias-label-tertiary);user-select:none;flex-shrink:0;justify-content:space-between;align-items:center;padding:0 10px;font-size:11px;display:flex}.n1ttEW_footerSyncStatus{align-items:center;gap:6px;display:flex}.n1ttEW_syncDot{background:var(--dsw-alias-state-success-primary);border-radius:50%;width:6px;height:6px}.n1ttEW_footerStats{align-items:center;gap:8px;display:flex}.n1ttEW_loadMoreLink{color:var(--dsw-alias-state-business-primary);cursor:pointer;font-weight:500}.n1ttEW_loadMoreLink:hover{text-decoration:underline}@container (width<=680px){.n1ttEW_workstationLayout{flex-direction:column}.n1ttEW_tablePane{flex:auto;min-height:160px}.n1ttEW_detailsPane{border-top:.5px solid var(--dsw-alias-border-l2);flex-shrink:0;max-height:340px;border-left:none!important;width:100%!important}}";
321
+ const tagId$1 = "@civilization/dsh-experimental-git/GitBody.module.css";
322
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
323
+ const tag = document.createElement("style");
324
+ tag.dataset.plugin = "@civilization/dsh-experimental-git";
325
+ tag.dataset.pluginCss = tagId$1;
326
+ tag.textContent = css$1;
327
+ document.head.appendChild(tag);
328
+ }
329
+ var GitBody_module_css_default = {
330
+ "actionTextBtn": "n1ttEW_actionTextBtn",
331
+ "addStat": "n1ttEW_addStat",
332
+ "aheadText": "n1ttEW_aheadText",
333
+ "authorAvatar": "n1ttEW_authorAvatar",
334
+ "authorCol": "n1ttEW_authorCol",
335
+ "authorNameText": "n1ttEW_authorNameText",
336
+ "behindText": "n1ttEW_behindText",
337
+ "branchBadge": "n1ttEW_branchBadge",
338
+ "branchIcon": "n1ttEW_branchIcon",
339
+ "branchInfo": "n1ttEW_branchInfo",
340
+ "colHeaderTitle": "n1ttEW_colHeaderTitle",
341
+ "commitBox": "n1ttEW_commitBox",
342
+ "commitBtn": "n1ttEW_commitBtn",
343
+ "commitButtonRow": "n1ttEW_commitButtonRow",
344
+ "commitDetailPanel": "n1ttEW_commitDetailPanel",
345
+ "commitPushBtn": "n1ttEW_commitPushBtn",
346
+ "commitTextarea": "n1ttEW_commitTextarea",
347
+ "content": "n1ttEW_content",
348
+ "delStat": "n1ttEW_delStat",
349
+ "detailFileItem": "n1ttEW_detailFileItem",
350
+ "detailFilesList": "n1ttEW_detailFilesList",
351
+ "detailHeader": "n1ttEW_detailHeader",
352
+ "detailMetaRow": "n1ttEW_detailMetaRow",
353
+ "detailSubject": "n1ttEW_detailSubject",
354
+ "detailsBody": "n1ttEW_detailsBody",
355
+ "detailsBottomActions": "n1ttEW_detailsBottomActions",
356
+ "detailsContent": "n1ttEW_detailsContent",
357
+ "detailsHeader": "n1ttEW_detailsHeader",
358
+ "detailsMetaGrid": "n1ttEW_detailsMetaGrid",
359
+ "detailsMetaLabel": "n1ttEW_detailsMetaLabel",
360
+ "detailsMetaRow": "n1ttEW_detailsMetaRow",
361
+ "detailsMetaVal": "n1ttEW_detailsMetaVal",
362
+ "detailsPane": "n1ttEW_detailsPane",
363
+ "detailsParentLink": "n1ttEW_detailsParentLink",
364
+ "detailsSectionTitle": "n1ttEW_detailsSectionTitle",
365
+ "detailsSubject": "n1ttEW_detailsSubject",
366
+ "diffAdd": "n1ttEW_diffAdd",
367
+ "diffDel": "n1ttEW_diffDel",
368
+ "diffHunk": "n1ttEW_diffHunk",
369
+ "diffLine": "n1ttEW_diffLine",
370
+ "diffViewer": "n1ttEW_diffViewer",
371
+ "emptyState": "n1ttEW_emptyState",
372
+ "fileDir": "n1ttEW_fileDir",
373
+ "fileItem": "n1ttEW_fileItem",
374
+ "fileItemActions": "n1ttEW_fileItemActions",
375
+ "fileLeft": "n1ttEW_fileLeft",
376
+ "fileList": "n1ttEW_fileList",
377
+ "fileMiniBtn": "n1ttEW_fileMiniBtn",
378
+ "fileName": "n1ttEW_fileName",
379
+ "footerStats": "n1ttEW_footerStats",
380
+ "footerSyncStatus": "n1ttEW_footerSyncStatus",
381
+ "graphOverlaySvg": "n1ttEW_graphOverlaySvg",
382
+ "graphSvg": "n1ttEW_graphSvg",
383
+ "header": "n1ttEW_header",
384
+ "headerActions": "n1ttEW_headerActions",
385
+ "iconButton": "n1ttEW_iconButton",
386
+ "loadMoreLink": "n1ttEW_loadMoreLink",
387
+ "locateGlowRing": "n1ttEW_locateGlowRing",
388
+ "mainlineToggleBtn": "n1ttEW_mainlineToggleBtn",
389
+ "mainlineToggleBtnActive": "n1ttEW_mainlineToggleBtnActive",
390
+ "mainlineToggleGroup": "n1ttEW_mainlineToggleGroup",
391
+ "numstat": "n1ttEW_numstat",
392
+ "pulseRing": "n1ttEW_pulseRing",
393
+ "refBadge": "n1ttEW_refBadge",
394
+ "refBranch": "n1ttEW_refBranch",
395
+ "refHead": "n1ttEW_refHead",
396
+ "refRemote": "n1ttEW_refRemote",
397
+ "refTag": "n1ttEW_refTag",
398
+ "root": "n1ttEW_root",
399
+ "rowGlow": "n1ttEW_rowGlow",
400
+ "section": "n1ttEW_section",
401
+ "sectionActions": "n1ttEW_sectionActions",
402
+ "sectionHeader": "n1ttEW_sectionHeader",
403
+ "sectionTitle": "n1ttEW_sectionTitle",
404
+ "shaCol": "n1ttEW_shaCol",
405
+ "spin": "n1ttEW_spin",
406
+ "spinning": "n1ttEW_spinning",
407
+ "statusA": "n1ttEW_statusA",
408
+ "statusAheadBehind": "n1ttEW_statusAheadBehind",
409
+ "statusBadge": "n1ttEW_statusBadge",
410
+ "statusD": "n1ttEW_statusD",
411
+ "statusM": "n1ttEW_statusM",
412
+ "statusU": "n1ttEW_statusU",
413
+ "subjectCol": "n1ttEW_subjectCol",
414
+ "syncDot": "n1ttEW_syncDot",
415
+ "tab": "n1ttEW_tab",
416
+ "tabActive": "n1ttEW_tabActive",
417
+ "tabCount": "n1ttEW_tabCount",
418
+ "tablePane": "n1ttEW_tablePane",
419
+ "tabs": "n1ttEW_tabs",
420
+ "tagActions": "n1ttEW_tagActions",
421
+ "tagAnnotatedBadge": "n1ttEW_tagAnnotatedBadge",
422
+ "tagAuthor": "n1ttEW_tagAuthor",
423
+ "tagCard": "n1ttEW_tagCard",
424
+ "tagCardHeader": "n1ttEW_tagCardHeader",
425
+ "tagForm": "n1ttEW_tagForm",
426
+ "tagFormActions": "n1ttEW_tagFormActions",
427
+ "tagFormTitle": "n1ttEW_tagFormTitle",
428
+ "tagList": "n1ttEW_tagList",
429
+ "tagLocateBtn": "n1ttEW_tagLocateBtn",
430
+ "tagMessage": "n1ttEW_tagMessage",
431
+ "tagMetaFooter": "n1ttEW_tagMetaFooter",
432
+ "tagName": "n1ttEW_tagName",
433
+ "tagShaPill": "n1ttEW_tagShaPill",
434
+ "tagTitleRow": "n1ttEW_tagTitleRow",
435
+ "timeCol": "n1ttEW_timeCol",
436
+ "treeActionBtn": "n1ttEW_treeActionBtn",
437
+ "treeAuthor": "n1ttEW_treeAuthor",
438
+ "treeBody": "n1ttEW_treeBody",
439
+ "treeContainer": "n1ttEW_treeContainer",
440
+ "treeFilterRow": "n1ttEW_treeFilterRow",
441
+ "treeHash": "n1ttEW_treeHash",
442
+ "treeRow": "n1ttEW_treeRow",
443
+ "treeRowActions": "n1ttEW_treeRowActions",
444
+ "treeRowGrid": "n1ttEW_treeRowGrid",
445
+ "treeRowGridSelected": "n1ttEW_treeRowGridSelected",
446
+ "treeRowHighlighted": "n1ttEW_treeRowHighlighted",
447
+ "treeRowSelected": "n1ttEW_treeRowSelected",
448
+ "treeSearchInput": "n1ttEW_treeSearchInput",
449
+ "treeStatusFooter": "n1ttEW_treeStatusFooter",
450
+ "treeSubject": "n1ttEW_treeSubject",
451
+ "treeTableHeader": "n1ttEW_treeTableHeader",
452
+ "treeTime": "n1ttEW_treeTime",
453
+ "typeBadge": "n1ttEW_typeBadge",
454
+ "typeChore": "n1ttEW_typeChore",
455
+ "typeDocs": "n1ttEW_typeDocs",
456
+ "typeFeat": "n1ttEW_typeFeat",
457
+ "typeFix": "n1ttEW_typeFix",
458
+ "typeMerge": "n1ttEW_typeMerge",
459
+ "typeRefactor": "n1ttEW_typeRefactor",
460
+ "typeRelease": "n1ttEW_typeRelease",
461
+ "typeRevert": "n1ttEW_typeRevert",
462
+ "typeStyle": "n1ttEW_typeStyle",
463
+ "typeTest": "n1ttEW_typeTest",
464
+ "workstationLayout": "n1ttEW_workstationLayout"
465
+ };
466
+ //#endregion
467
+ //#region lib/types/client/GitBody.js
468
+ /**
469
+ * IntelliJ IDEA-Grade Git Tool Window Component.
470
+ * Supports DAG commit topology graph visualization, working tree staging, commit console,
471
+ * branch switcher, and unified diff inspector.
472
+ */
473
+ function getTypeBadgeClass(type) {
474
+ switch (type) {
475
+ case "feat": return GitBody_module_css_default.typeFeat ?? "";
476
+ case "fix": return GitBody_module_css_default.typeFix ?? "";
477
+ case "style": return GitBody_module_css_default.typeStyle ?? "";
478
+ case "refactor": return GitBody_module_css_default.typeRefactor ?? "";
479
+ case "release": return GitBody_module_css_default.typeRelease ?? "";
480
+ case "merge": return GitBody_module_css_default.typeMerge ?? "";
481
+ case "test": return GitBody_module_css_default.typeTest ?? "";
482
+ case "docs": return GitBody_module_css_default.typeDocs ?? "";
483
+ case "revert": return GitBody_module_css_default.typeRevert ?? "";
484
+ default: return GitBody_module_css_default.typeChore ?? "";
485
+ }
486
+ }
487
+ /**
488
+ * Render color-coded unified diff lines.
489
+ */
490
+ function DiffViewer({ diffText }) {
491
+ if (!diffText.trim()) return (0, react_jsx_runtime.jsx)("div", {
492
+ className: GitBody_module_css_default.diffViewer,
493
+ children: "无代码内容变动"
494
+ });
495
+ const lines = diffText.split("\n");
496
+ return (0, react_jsx_runtime.jsx)("div", {
497
+ className: GitBody_module_css_default.diffViewer,
498
+ children: lines.map((line, idx) => {
499
+ let lineClass = GitBody_module_css_default.diffLine;
500
+ if (line.startsWith("+") && !line.startsWith("+++")) lineClass = `${GitBody_module_css_default.diffLine} ${GitBody_module_css_default.diffAdd}`;
501
+ else if (line.startsWith("-") && !line.startsWith("---")) lineClass = `${GitBody_module_css_default.diffLine} ${GitBody_module_css_default.diffDel}`;
502
+ else if (line.startsWith("@@")) lineClass = `${GitBody_module_css_default.diffLine} ${GitBody_module_css_default.diffHunk}`;
503
+ return (0, react_jsx_runtime.jsx)("div", {
504
+ className: lineClass,
505
+ children: line || " "
506
+ }, idx);
507
+ })
508
+ });
509
+ }
510
+ /**
511
+ * Main Git Body Component.
512
+ */
513
+ const GitBody = (0, react.memo)(function GitBody(props) {
514
+ const { t, sessionId, getStatus, getLog, getCommitDetails, getDiff, getBranches, getTags, createTag, deleteTag, checkout, stage, unstage, discard, commit, fetch: fetchGit, pull, push } = props;
515
+ const [activeTab, setActiveTab] = (0, react.useState)("changes");
516
+ const [loading, setLoading] = (0, react.useState)(false);
517
+ const [status, setStatus] = (0, react.useState)(null);
518
+ const [commits, setCommits] = (0, react.useState)([]);
519
+ const [branches, setBranches] = (0, react.useState)(null);
520
+ const [tags, setTags] = (0, react.useState)([]);
521
+ const [commitMessage, setCommitMessage] = (0, react.useState)("");
522
+ const [committing, setCommitting] = (0, react.useState)(false);
523
+ const [selectedFileDiff, setSelectedFileDiff] = (0, react.useState)(null);
524
+ const [selectedCommitHash, setSelectedCommitHash] = (0, react.useState)(null);
525
+ const [commitDetail, setCommitDetail] = (0, react.useState)(null);
526
+ const [highlightedCommitHash, setHighlightedCommitHash] = (0, react.useState)(null);
527
+ const [locatedNotice, setLocatedNotice] = (0, react.useState)(null);
528
+ const [treeSearch, setTreeSearch] = (0, react.useState)("");
529
+ const [filterMode, setFilterMode] = (0, react.useState)("all");
530
+ const [branchFilter, setBranchFilter] = (0, react.useState)("");
531
+ const [newBranchName, setNewBranchName] = (0, react.useState)("");
532
+ const [creatingBranch, setCreatingBranch] = (0, react.useState)(false);
533
+ const [tagFilter, setTagFilter] = (0, react.useState)("");
534
+ const [creatingTag, setCreatingTag] = (0, react.useState)(false);
535
+ const [newTagName, setNewTagName] = (0, react.useState)("");
536
+ const [newTagCommit, setNewTagCommit] = (0, react.useState)("");
537
+ const [newTagMessage, setNewTagMessage] = (0, react.useState)("");
538
+ const refresh = (0, react.useCallback)(async () => {
539
+ setLoading(true);
540
+ try {
541
+ const [statusRes, logRes, branchRes, tagRes] = await Promise.all([
542
+ getStatus(sessionId).catch(() => null),
543
+ getLog(sessionId, 50).catch(() => []),
544
+ getBranches(sessionId).catch(() => null),
545
+ getTags(sessionId).catch(() => [])
546
+ ]);
547
+ if (statusRes) setStatus(statusRes);
548
+ setCommits(logRes);
549
+ if (branchRes) setBranches(branchRes);
550
+ setTags(tagRes);
551
+ } finally {
552
+ setLoading(false);
553
+ }
554
+ }, [
555
+ getBranches,
556
+ getLog,
557
+ getStatus,
558
+ getTags,
559
+ sessionId
560
+ ]);
561
+ (0, react.useEffect)(() => {
562
+ refresh();
563
+ }, [refresh]);
564
+ const handleSelectCommit = (0, react.useCallback)(async (hash) => {
565
+ if (selectedCommitHash === hash) {
566
+ setSelectedCommitHash(null);
567
+ setCommitDetail(null);
568
+ return;
569
+ }
570
+ setSelectedCommitHash(hash);
571
+ try {
572
+ setCommitDetail(await getCommitDetails(sessionId, hash) ?? null);
573
+ } catch {
574
+ setCommitDetail(null);
575
+ }
576
+ }, [
577
+ getCommitDetails,
578
+ selectedCommitHash,
579
+ sessionId
580
+ ]);
581
+ const handleViewDiff = (0, react.useCallback)(async (path, staged, commitHash) => {
582
+ try {
583
+ setSelectedFileDiff({
584
+ path,
585
+ staged,
586
+ diff: (await getDiff(sessionId, {
587
+ filePath: path,
588
+ staged,
589
+ ...commitHash !== void 0 ? { commit: commitHash } : {}
590
+ })).rawDiff
591
+ });
592
+ } catch {
593
+ setSelectedFileDiff(null);
594
+ }
595
+ }, [getDiff, sessionId]);
596
+ const handleStage = (0, react.useCallback)(async (paths) => {
597
+ await stage(sessionId, paths);
598
+ await refresh();
599
+ }, [
600
+ refresh,
601
+ sessionId,
602
+ stage
603
+ ]);
604
+ const handleUnstage = (0, react.useCallback)(async (paths) => {
605
+ await unstage(sessionId, paths);
606
+ await refresh();
607
+ }, [
608
+ refresh,
609
+ sessionId,
610
+ unstage
611
+ ]);
612
+ const handleDiscard = (0, react.useCallback)(async (paths) => {
613
+ if (confirm(`确认放弃对 ${paths.length} 个文件的所有更改吗?此操作无法撤销。`)) {
614
+ await discard(sessionId, paths);
615
+ await refresh();
616
+ }
617
+ }, [
618
+ discard,
619
+ refresh,
620
+ sessionId
621
+ ]);
622
+ const handleCommit = (0, react.useCallback)(async (andPush = false) => {
623
+ const trimmed = commitMessage.trim();
624
+ if (!trimmed) {
625
+ alert(t("commit.emptyWarning"));
626
+ return;
627
+ }
628
+ setCommitting(true);
629
+ try {
630
+ const res = await commit(sessionId, trimmed);
631
+ if (res.success) {
632
+ setCommitMessage("");
633
+ if (andPush) await push(sessionId);
634
+ await refresh();
635
+ } else alert(res.message || "提交失败");
636
+ } finally {
637
+ setCommitting(false);
638
+ }
639
+ }, [
640
+ commit,
641
+ commitMessage,
642
+ push,
643
+ refresh,
644
+ sessionId,
645
+ t
646
+ ]);
647
+ const handleCommitKeyDown = (0, react.useCallback)((e) => {
648
+ if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
649
+ e.preventDefault();
650
+ handleCommit(false);
651
+ }
652
+ }, [handleCommit]);
653
+ const handleCheckoutBranch = (0, react.useCallback)(async (bName, create = false) => {
654
+ const res = await checkout(sessionId, bName, create);
655
+ if (res.success) {
656
+ setCreatingBranch(false);
657
+ setNewBranchName("");
658
+ await refresh();
659
+ } else alert(res.message || "检出失败");
660
+ }, [
661
+ checkout,
662
+ refresh,
663
+ sessionId
664
+ ]);
665
+ const handleLocateCommit = (0, react.useCallback)(async (commitHash, tagName) => {
666
+ setActiveTab("tree");
667
+ let found = commits.find((c) => c.hash.startsWith(commitHash) || commitHash.startsWith(c.hash));
668
+ if (!found) try {
669
+ const deepLogs = await getLog(sessionId, 200);
670
+ setCommits(deepLogs);
671
+ found = deepLogs.find((c) => c.hash.startsWith(commitHash) || commitHash.startsWith(c.hash));
672
+ } catch {}
673
+ if (found) {
674
+ setSelectedCommitHash(found.hash);
675
+ setHighlightedCommitHash(found.hash);
676
+ if (tagName) {
677
+ setLocatedNotice(t("tag.locatedNotice", { name: tagName }));
678
+ setTimeout(() => {
679
+ setLocatedNotice(null);
680
+ }, 3e3);
681
+ }
682
+ handleSelectCommit(found.hash);
683
+ setTimeout(() => {
684
+ document.getElementById(`git-commit-${found.hash}`)?.scrollIntoView({
685
+ behavior: "smooth",
686
+ block: "center"
687
+ });
688
+ }, 50);
689
+ setTimeout(() => {
690
+ setHighlightedCommitHash(null);
691
+ }, 3500);
692
+ }
693
+ }, [
694
+ commits,
695
+ getLog,
696
+ handleSelectCommit,
697
+ sessionId,
698
+ t
699
+ ]);
700
+ const handleCreateTag = (0, react.useCallback)(async () => {
701
+ const name = newTagName.trim();
702
+ if (!name) {
703
+ alert("请输入标签名称");
704
+ return;
705
+ }
706
+ const res = await createTag(sessionId, name, newTagCommit.trim() || void 0, newTagMessage.trim() || void 0);
707
+ if (res.success) {
708
+ setCreatingTag(false);
709
+ setNewTagName("");
710
+ setNewTagCommit("");
711
+ setNewTagMessage("");
712
+ await refresh();
713
+ } else alert(res.message || "创建标签失败");
714
+ }, [
715
+ createTag,
716
+ newTagCommit,
717
+ newTagMessage,
718
+ newTagName,
719
+ refresh,
720
+ sessionId
721
+ ]);
722
+ const handleDeleteTag = (0, react.useCallback)(async (tagName) => {
723
+ if (confirm(t("tag.deleteConfirm", { name: tagName }))) {
724
+ const res = await deleteTag(sessionId, tagName);
725
+ if (res.success) await refresh();
726
+ else alert(res.message || "删除标签失败");
727
+ }
728
+ }, [
729
+ deleteTag,
730
+ refresh,
731
+ sessionId,
732
+ t
733
+ ]);
734
+ const filteredLocalBranches = (0, react.useMemo)(() => {
735
+ if (!branches?.local) return [];
736
+ const q = branchFilter.trim().toLowerCase();
737
+ return q ? branches.local.filter((b) => b.name.toLowerCase().includes(q)) : branches.local;
738
+ }, [branches?.local, branchFilter]);
739
+ const filteredRemoteBranches = (0, react.useMemo)(() => {
740
+ if (!branches?.remote) return [];
741
+ const q = branchFilter.trim().toLowerCase();
742
+ return q ? branches.remote.filter((b) => b.name.toLowerCase().includes(q)) : branches.remote;
743
+ }, [branches?.remote, branchFilter]);
744
+ const filteredTags = (0, react.useMemo)(() => {
745
+ const q = tagFilter.trim().toLowerCase();
746
+ if (!q) return tags;
747
+ return tags.filter((item) => item.name.toLowerCase().includes(q) || item.shortHash.toLowerCase().includes(q) || item.commitHash.toLowerCase().includes(q) || item.message.toLowerCase().includes(q) || item.author.toLowerCase().includes(q));
748
+ }, [tags, tagFilter]);
749
+ const filteredCommits = (0, react.useMemo)(() => {
750
+ let list = commits;
751
+ if (filterMode === "mainline") list = list.filter((c) => (c.lane ?? 0) === 0);
752
+ const q = treeSearch.trim().toLowerCase();
753
+ if (q) list = list.filter((c) => c.subject.toLowerCase().includes(q) || c.hash.toLowerCase().includes(q) || c.shortHash.toLowerCase().includes(q) || c.author.toLowerCase().includes(q) || c.refs && c.refs.some((r) => r.toLowerCase().includes(q)));
754
+ return list;
755
+ }, [
756
+ commits,
757
+ filterMode,
758
+ treeSearch
759
+ ]);
760
+ const handleLoadMore = (0, react.useCallback)(async () => {
761
+ setLoading(true);
762
+ try {
763
+ setCommits(await getLog(sessionId, commits.length + 50));
764
+ } finally {
765
+ setLoading(false);
766
+ }
767
+ }, [
768
+ commits.length,
769
+ getLog,
770
+ sessionId
771
+ ]);
772
+ const dagGraph = (0, react.useMemo)(() => computeDagGraph(filteredCommits), [filteredCommits]);
773
+ const graphColWidth = dagGraph.graphWidth;
774
+ if (!status || !status.isRepo) return (0, react_jsx_runtime.jsx)("div", {
775
+ className: GitBody_module_css_default.root,
776
+ children: (0, react_jsx_runtime.jsxs)("div", {
777
+ className: GitBody_module_css_default.emptyState,
778
+ children: [(0, react_jsx_runtime.jsx)("svg", {
779
+ viewBox: "0 0 16 16",
780
+ fill: "currentColor",
781
+ children: (0, react_jsx_runtime.jsx)("path", { d: "M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5v-9zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8V1.5z" })
782
+ }), (0, react_jsx_runtime.jsx)("div", { children: t("status.notRepo") })]
783
+ })
784
+ });
785
+ const stagedCount = status.staged.length;
786
+ const unstagedCount = status.unstaged.length;
787
+ const untrackedCount = status.untracked.length;
788
+ const totalChanges = status.totalChanges;
789
+ return (0, react_jsx_runtime.jsxs)("div", {
790
+ className: GitBody_module_css_default.root,
791
+ children: [
792
+ (0, react_jsx_runtime.jsxs)("div", {
793
+ className: GitBody_module_css_default.header,
794
+ children: [(0, react_jsx_runtime.jsxs)("div", {
795
+ className: GitBody_module_css_default.branchInfo,
796
+ children: [(0, react_jsx_runtime.jsxs)("span", {
797
+ className: GitBody_module_css_default.branchBadge,
798
+ title: `当前分支: ${status.branch}`,
799
+ children: [(0, react_jsx_runtime.jsx)("svg", {
800
+ className: GitBody_module_css_default.branchIcon,
801
+ width: "12",
802
+ height: "12",
803
+ viewBox: "0 0 16 16",
804
+ fill: "currentColor",
805
+ children: (0, react_jsx_runtime.jsx)("path", { d: "M11.75 2.5a1.75 1.75 0 1 0-2.45 1.606V6.5a1.5 1.5 0 0 1-1.5 1.5H5.8A2.75 2.75 0 0 0 3.5 6.25V4.106a1.75 1.75 0 1 0-1.5 0v7.788a1.75 1.75 0 1 0 1.5 0V8.25A1.25 1.25 0 0 1 4.75 7h3a3 3 0 0 0 3-3V4.106a1.75 1.75 0 0 0 1-1.606z" })
806
+ }), status.branch || "HEAD"]
807
+ }), (status.ahead > 0 || status.behind > 0) && (0, react_jsx_runtime.jsxs)("div", {
808
+ className: GitBody_module_css_default.statusAheadBehind,
809
+ children: [status.ahead > 0 && (0, react_jsx_runtime.jsxs)("span", {
810
+ className: GitBody_module_css_default.aheadText,
811
+ children: ["↑", status.ahead]
812
+ }), status.behind > 0 && (0, react_jsx_runtime.jsxs)("span", {
813
+ className: GitBody_module_css_default.behindText,
814
+ children: ["↓", status.behind]
815
+ })]
816
+ })]
817
+ }), (0, react_jsx_runtime.jsxs)("div", {
818
+ className: GitBody_module_css_default.headerActions,
819
+ children: [
820
+ (0, react_jsx_runtime.jsx)("button", {
821
+ type: "button",
822
+ className: GitBody_module_css_default.iconButton,
823
+ title: t("actions.fetch"),
824
+ onClick: () => {
825
+ fetchGit(sessionId).then(() => refresh());
826
+ },
827
+ children: (0, react_jsx_runtime.jsx)("svg", {
828
+ width: "14",
829
+ height: "14",
830
+ viewBox: "0 0 16 16",
831
+ fill: "currentColor",
832
+ children: (0, react_jsx_runtime.jsx)("path", { d: "M1.75 3a.75.75 0 0 0 0 1.5h8.5a3.25 3.25 0 0 1 3.25 3.25v2.44l1.72-1.72a.75.75 0 1 1 1.06 1.06l-3 3a.75.75 0 0 1-1.06 0l-3-3a.75.75 0 1 1 1.06-1.06l1.72 1.72V7.75A1.75 1.75 0 0 0 10.25 6H1.75a.75.75 0 0 0 0-1.5z" })
833
+ })
834
+ }),
835
+ (0, react_jsx_runtime.jsx)("button", {
836
+ type: "button",
837
+ className: GitBody_module_css_default.iconButton,
838
+ title: "拉取 (Pull)",
839
+ onClick: () => {
840
+ pull(sessionId).then(() => refresh());
841
+ },
842
+ children: (0, react_jsx_runtime.jsx)("svg", {
843
+ width: "14",
844
+ height: "14",
845
+ viewBox: "0 0 16 16",
846
+ fill: "currentColor",
847
+ children: (0, react_jsx_runtime.jsx)("path", { d: "M13.03 8.22a.75.75 0 0 1 0 1.06l-4.5 4.5a.75.75 0 0 1-1.06 0l-4.5-4.5a.75.75 0 0 1 1.06-1.06L7.5 11.69V2.75a.75.75 0 0 1 1.5 0v8.94l3.47-3.47a.75.75 0 0 1 1.06 0z" })
848
+ })
849
+ }),
850
+ (0, react_jsx_runtime.jsx)("button", {
851
+ type: "button",
852
+ className: GitBody_module_css_default.iconButton,
853
+ title: "推送 (Push)",
854
+ onClick: () => {
855
+ push(sessionId).then(() => refresh());
856
+ },
857
+ children: (0, react_jsx_runtime.jsx)("svg", {
858
+ width: "14",
859
+ height: "14",
860
+ viewBox: "0 0 16 16",
861
+ fill: "currentColor",
862
+ children: (0, react_jsx_runtime.jsx)("path", { d: "M2.97 7.78a.75.75 0 0 1 0-1.06l4.5-4.5a.75.75 0 0 1 1.06 0l4.5 4.5a.75.75 0 1 1-1.06 1.06L8.5 4.31v8.94a.75.75 0 0 1-1.5 0V4.31L3.53 7.78a.75.75 0 0 1-1.06 0z" })
863
+ })
864
+ }),
865
+ (0, react_jsx_runtime.jsx)("button", {
866
+ type: "button",
867
+ className: `${GitBody_module_css_default.iconButton} ${loading ? GitBody_module_css_default.spinning : ""}`,
868
+ title: "刷新",
869
+ onClick: () => {
870
+ refresh();
871
+ },
872
+ children: (0, react_jsx_runtime.jsx)("svg", {
873
+ width: "14",
874
+ height: "14",
875
+ viewBox: "0 0 16 16",
876
+ fill: "currentColor",
877
+ children: (0, react_jsx_runtime.jsx)("path", { d: "M1.705 8.005a.75.75 0 0 1 .834.656 5.5 5.5 0 0 0 9.592 2.97l-1.204-1.204a.25.25 0 0 1 .177-.427h3.646a.25.25 0 0 1 .25.25v3.646a.25.25 0 0 1-.427.177l-1.38-1.38A7.002 7.002 0 0 1 1.05 8.84a.75.75 0 0 1 .655-.835zm12.59-1.01a.75.75 0 0 1-.834-.656 5.5 5.5 0 0 0-9.592-2.97l1.204 1.204a.25.25 0 0 1-.177.427H1.25a.25.25 0 0 1-.25-.25V1.104a.25.25 0 0 1 .427-.177l1.38 1.38A7.002 7.002 0 0 1 14.95 7.16a.75.75 0 0 1-.655.835z" })
878
+ })
879
+ })
880
+ ]
881
+ })]
882
+ }),
883
+ (0, react_jsx_runtime.jsxs)("div", {
884
+ className: GitBody_module_css_default.tabs,
885
+ children: [
886
+ (0, react_jsx_runtime.jsxs)("button", {
887
+ type: "button",
888
+ className: `${GitBody_module_css_default.tab} ${activeTab === "changes" ? GitBody_module_css_default.tabActive : ""}`,
889
+ onClick: () => {
890
+ setActiveTab("changes");
891
+ },
892
+ children: [t("tabs.changes"), totalChanges > 0 && (0, react_jsx_runtime.jsx)("span", {
893
+ className: GitBody_module_css_default.tabCount,
894
+ children: totalChanges
895
+ })]
896
+ }),
897
+ (0, react_jsx_runtime.jsxs)("button", {
898
+ type: "button",
899
+ className: `${GitBody_module_css_default.tab} ${activeTab === "tree" ? GitBody_module_css_default.tabActive : ""}`,
900
+ onClick: () => {
901
+ setActiveTab("tree");
902
+ },
903
+ children: [t("tabs.tree"), (0, react_jsx_runtime.jsx)("span", {
904
+ className: GitBody_module_css_default.tabCount,
905
+ children: commits.length
906
+ })]
907
+ }),
908
+ (0, react_jsx_runtime.jsx)("button", {
909
+ type: "button",
910
+ className: `${GitBody_module_css_default.tab} ${activeTab === "branches" ? GitBody_module_css_default.tabActive : ""}`,
911
+ onClick: () => {
912
+ setActiveTab("branches");
913
+ },
914
+ children: t("tabs.branches")
915
+ }),
916
+ (0, react_jsx_runtime.jsxs)("button", {
917
+ type: "button",
918
+ className: `${GitBody_module_css_default.tab} ${activeTab === "tags" ? GitBody_module_css_default.tabActive : ""}`,
919
+ onClick: () => {
920
+ setActiveTab("tags");
921
+ },
922
+ children: [t("tabs.tags"), tags.length > 0 && (0, react_jsx_runtime.jsx)("span", {
923
+ className: GitBody_module_css_default.tabCount,
924
+ children: tags.length
925
+ })]
926
+ })
927
+ ]
928
+ }),
929
+ locatedNotice && (0, react_jsx_runtime.jsxs)("div", {
930
+ style: {
931
+ padding: "6px 12px",
932
+ background: "color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent)",
933
+ color: "var(--dsw-alias-state-business-primary)",
934
+ fontSize: "11px",
935
+ fontWeight: 600,
936
+ display: "flex",
937
+ alignItems: "center",
938
+ gap: "6px",
939
+ borderBottom: "0.5px solid var(--dsw-alias-border-l2)"
940
+ },
941
+ children: [(0, react_jsx_runtime.jsx)("span", { children: "🎯" }), (0, react_jsx_runtime.jsx)("span", { children: locatedNotice })]
942
+ }),
943
+ (0, react_jsx_runtime.jsxs)("div", {
944
+ className: GitBody_module_css_default.content,
945
+ children: [
946
+ activeTab === "changes" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [totalChanges === 0 ? (0, react_jsx_runtime.jsxs)("div", {
947
+ className: GitBody_module_css_default.emptyState,
948
+ children: [(0, react_jsx_runtime.jsx)("svg", {
949
+ viewBox: "0 0 16 16",
950
+ fill: "currentColor",
951
+ children: (0, react_jsx_runtime.jsx)("path", { d: "M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0z" })
952
+ }), (0, react_jsx_runtime.jsx)("div", { children: t("status.clean") })]
953
+ }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
954
+ stagedCount > 0 && (0, react_jsx_runtime.jsxs)("div", {
955
+ className: GitBody_module_css_default.section,
956
+ children: [(0, react_jsx_runtime.jsxs)("div", {
957
+ className: GitBody_module_css_default.sectionHeader,
958
+ children: [(0, react_jsx_runtime.jsxs)("div", {
959
+ className: GitBody_module_css_default.sectionTitle,
960
+ children: [(0, react_jsx_runtime.jsx)("span", {
961
+ className: `${GitBody_module_css_default.statusBadge} ${GitBody_module_css_default.statusA}`,
962
+ children: "✓"
963
+ }), (0, react_jsx_runtime.jsxs)("span", { children: [
964
+ t("status.staged"),
965
+ " (",
966
+ stagedCount,
967
+ ")"
968
+ ] })]
969
+ }), (0, react_jsx_runtime.jsx)("div", {
970
+ className: GitBody_module_css_default.sectionActions,
971
+ children: (0, react_jsx_runtime.jsx)("button", {
972
+ type: "button",
973
+ className: GitBody_module_css_default.actionTextBtn,
974
+ title: t("actions.unstageAll"),
975
+ onClick: () => {
976
+ handleUnstage("all");
977
+ },
978
+ children: "全部取消暂存"
979
+ })
980
+ })]
981
+ }), (0, react_jsx_runtime.jsx)("div", {
982
+ className: GitBody_module_css_default.fileList,
983
+ children: status.staged.map((f) => (0, react_jsx_runtime.jsxs)("div", {
984
+ className: GitBody_module_css_default.fileItem,
985
+ onClick: () => {
986
+ handleViewDiff(f.path, true);
987
+ },
988
+ children: [(0, react_jsx_runtime.jsxs)("div", {
989
+ className: GitBody_module_css_default.fileLeft,
990
+ children: [(0, react_jsx_runtime.jsx)("span", {
991
+ className: `${GitBody_module_css_default.statusBadge} ${GitBody_module_css_default.statusA}`,
992
+ children: f.status[0]?.toUpperCase() ?? "M"
993
+ }), (0, react_jsx_runtime.jsx)("span", {
994
+ className: GitBody_module_css_default.fileName,
995
+ children: f.path
996
+ })]
997
+ }), (0, react_jsx_runtime.jsx)("div", {
998
+ className: GitBody_module_css_default.fileItemActions,
999
+ children: (0, react_jsx_runtime.jsx)("button", {
1000
+ type: "button",
1001
+ className: GitBody_module_css_default.fileMiniBtn,
1002
+ title: t("actions.unstage"),
1003
+ onClick: (e) => {
1004
+ e.stopPropagation();
1005
+ handleUnstage([f.path]);
1006
+ },
1007
+ children: "-"
1008
+ })
1009
+ })]
1010
+ }, `staged-${f.path}`))
1011
+ })]
1012
+ }),
1013
+ unstagedCount > 0 && (0, react_jsx_runtime.jsxs)("div", {
1014
+ className: GitBody_module_css_default.section,
1015
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1016
+ className: GitBody_module_css_default.sectionHeader,
1017
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1018
+ className: GitBody_module_css_default.sectionTitle,
1019
+ children: [(0, react_jsx_runtime.jsx)("span", {
1020
+ className: `${GitBody_module_css_default.statusBadge} ${GitBody_module_css_default.statusM}`,
1021
+ children: "M"
1022
+ }), (0, react_jsx_runtime.jsxs)("span", { children: [
1023
+ t("status.unstaged"),
1024
+ " (",
1025
+ unstagedCount,
1026
+ ")"
1027
+ ] })]
1028
+ }), (0, react_jsx_runtime.jsx)("div", {
1029
+ className: GitBody_module_css_default.sectionActions,
1030
+ children: (0, react_jsx_runtime.jsx)("button", {
1031
+ type: "button",
1032
+ className: GitBody_module_css_default.actionTextBtn,
1033
+ title: t("actions.stageAll"),
1034
+ onClick: () => {
1035
+ handleStage("all");
1036
+ },
1037
+ children: "全部暂存"
1038
+ })
1039
+ })]
1040
+ }), (0, react_jsx_runtime.jsx)("div", {
1041
+ className: GitBody_module_css_default.fileList,
1042
+ children: status.unstaged.map((f) => (0, react_jsx_runtime.jsxs)("div", {
1043
+ className: GitBody_module_css_default.fileItem,
1044
+ onClick: () => {
1045
+ handleViewDiff(f.path, false);
1046
+ },
1047
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1048
+ className: GitBody_module_css_default.fileLeft,
1049
+ children: [(0, react_jsx_runtime.jsx)("span", {
1050
+ className: `${GitBody_module_css_default.statusBadge} ${GitBody_module_css_default.statusM}`,
1051
+ children: f.status[0]?.toUpperCase() ?? "M"
1052
+ }), (0, react_jsx_runtime.jsx)("span", {
1053
+ className: GitBody_module_css_default.fileName,
1054
+ children: f.path
1055
+ })]
1056
+ }), (0, react_jsx_runtime.jsxs)("div", {
1057
+ className: GitBody_module_css_default.fileItemActions,
1058
+ children: [(0, react_jsx_runtime.jsx)("button", {
1059
+ type: "button",
1060
+ className: GitBody_module_css_default.fileMiniBtn,
1061
+ title: t("actions.stage"),
1062
+ onClick: (e) => {
1063
+ e.stopPropagation();
1064
+ handleStage([f.path]);
1065
+ },
1066
+ children: "+"
1067
+ }), (0, react_jsx_runtime.jsx)("button", {
1068
+ type: "button",
1069
+ className: GitBody_module_css_default.fileMiniBtn,
1070
+ title: t("actions.discard"),
1071
+ onClick: (e) => {
1072
+ e.stopPropagation();
1073
+ handleDiscard([f.path]);
1074
+ },
1075
+ children: "↺"
1076
+ })]
1077
+ })]
1078
+ }, `unstaged-${f.path}`))
1079
+ })]
1080
+ }),
1081
+ untrackedCount > 0 && (0, react_jsx_runtime.jsxs)("div", {
1082
+ className: GitBody_module_css_default.section,
1083
+ children: [(0, react_jsx_runtime.jsx)("div", {
1084
+ className: GitBody_module_css_default.sectionHeader,
1085
+ children: (0, react_jsx_runtime.jsxs)("div", {
1086
+ className: GitBody_module_css_default.sectionTitle,
1087
+ children: [(0, react_jsx_runtime.jsx)("span", {
1088
+ className: `${GitBody_module_css_default.statusBadge} ${GitBody_module_css_default.statusU}`,
1089
+ children: "?"
1090
+ }), (0, react_jsx_runtime.jsxs)("span", { children: [
1091
+ t("status.untracked"),
1092
+ " (",
1093
+ untrackedCount,
1094
+ ")"
1095
+ ] })]
1096
+ })
1097
+ }), (0, react_jsx_runtime.jsx)("div", {
1098
+ className: GitBody_module_css_default.fileList,
1099
+ children: status.untracked.map((f) => (0, react_jsx_runtime.jsxs)("div", {
1100
+ className: GitBody_module_css_default.fileItem,
1101
+ onClick: () => {
1102
+ handleViewDiff(f.path, false);
1103
+ },
1104
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1105
+ className: GitBody_module_css_default.fileLeft,
1106
+ children: [(0, react_jsx_runtime.jsx)("span", {
1107
+ className: `${GitBody_module_css_default.statusBadge} ${GitBody_module_css_default.statusU}`,
1108
+ children: "?"
1109
+ }), (0, react_jsx_runtime.jsx)("span", {
1110
+ className: GitBody_module_css_default.fileName,
1111
+ children: f.path
1112
+ })]
1113
+ }), (0, react_jsx_runtime.jsx)("div", {
1114
+ className: GitBody_module_css_default.fileItemActions,
1115
+ children: (0, react_jsx_runtime.jsx)("button", {
1116
+ type: "button",
1117
+ className: GitBody_module_css_default.fileMiniBtn,
1118
+ title: t("actions.stage"),
1119
+ onClick: (e) => {
1120
+ e.stopPropagation();
1121
+ handleStage([f.path]);
1122
+ },
1123
+ children: "+"
1124
+ })
1125
+ })]
1126
+ }, `untracked-${f.path}`))
1127
+ })]
1128
+ }),
1129
+ (0, react_jsx_runtime.jsxs)("div", {
1130
+ className: GitBody_module_css_default.commitBox,
1131
+ children: [(0, react_jsx_runtime.jsx)("textarea", {
1132
+ className: GitBody_module_css_default.commitTextarea,
1133
+ placeholder: t("commit.placeholder"),
1134
+ value: commitMessage,
1135
+ onChange: (e) => {
1136
+ setCommitMessage(e.target.value);
1137
+ },
1138
+ onKeyDown: handleCommitKeyDown
1139
+ }), (0, react_jsx_runtime.jsxs)("div", {
1140
+ className: GitBody_module_css_default.commitButtonRow,
1141
+ children: [(0, react_jsx_runtime.jsx)("button", {
1142
+ type: "button",
1143
+ className: GitBody_module_css_default.commitPushBtn,
1144
+ disabled: committing || stagedCount === 0,
1145
+ onClick: () => {
1146
+ handleCommit(true);
1147
+ },
1148
+ children: t("actions.commitAndPush")
1149
+ }), (0, react_jsx_runtime.jsx)("button", {
1150
+ type: "button",
1151
+ className: GitBody_module_css_default.commitBtn,
1152
+ disabled: committing || stagedCount === 0,
1153
+ onClick: () => {
1154
+ handleCommit(false);
1155
+ },
1156
+ children: t("actions.commit")
1157
+ })]
1158
+ })]
1159
+ })
1160
+ ] }), selectedFileDiff && (0, react_jsx_runtime.jsxs)("div", {
1161
+ style: { marginTop: "8px" },
1162
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1163
+ style: {
1164
+ display: "flex",
1165
+ justifyContent: "space-between",
1166
+ alignItems: "center",
1167
+ marginBottom: "4px"
1168
+ },
1169
+ children: [(0, react_jsx_runtime.jsxs)("span", {
1170
+ style: {
1171
+ fontSize: "11px",
1172
+ fontWeight: 600
1173
+ },
1174
+ children: ["差异对比: ", selectedFileDiff.path]
1175
+ }), (0, react_jsx_runtime.jsx)("button", {
1176
+ type: "button",
1177
+ className: GitBody_module_css_default.actionTextBtn,
1178
+ onClick: () => {
1179
+ setSelectedFileDiff(null);
1180
+ },
1181
+ children: "关闭"
1182
+ })]
1183
+ }), (0, react_jsx_runtime.jsx)(DiffViewer, { diffText: selectedFileDiff.diff })]
1184
+ })] }),
1185
+ activeTab === "tree" && (0, react_jsx_runtime.jsxs)("div", {
1186
+ style: {
1187
+ display: "flex",
1188
+ flexDirection: "column",
1189
+ flex: "1 1 auto",
1190
+ minHeight: 0,
1191
+ overflow: "hidden"
1192
+ },
1193
+ children: [
1194
+ (0, react_jsx_runtime.jsxs)("div", {
1195
+ className: GitBody_module_css_default.treeFilterRow,
1196
+ children: [(0, react_jsx_runtime.jsx)("input", {
1197
+ className: GitBody_module_css_default.treeSearchInput,
1198
+ placeholder: t("tree.searchPlaceholder"),
1199
+ value: treeSearch,
1200
+ onChange: (e) => {
1201
+ setTreeSearch(e.target.value);
1202
+ }
1203
+ }), (0, react_jsx_runtime.jsxs)("div", {
1204
+ className: GitBody_module_css_default.mainlineToggleGroup,
1205
+ children: [(0, react_jsx_runtime.jsx)("button", {
1206
+ type: "button",
1207
+ className: `${GitBody_module_css_default.mainlineToggleBtn} ${filterMode === "all" ? GitBody_module_css_default.mainlineToggleBtnActive : ""}`,
1208
+ onClick: () => {
1209
+ setFilterMode("all");
1210
+ },
1211
+ children: t("tree.filterAll")
1212
+ }), (0, react_jsx_runtime.jsx)("button", {
1213
+ type: "button",
1214
+ className: `${GitBody_module_css_default.mainlineToggleBtn} ${filterMode === "mainline" ? GitBody_module_css_default.mainlineToggleBtnActive : ""}`,
1215
+ onClick: () => {
1216
+ setFilterMode("mainline");
1217
+ },
1218
+ children: t("tree.filterMainline")
1219
+ })]
1220
+ })]
1221
+ }),
1222
+ (0, react_jsx_runtime.jsxs)("div", {
1223
+ className: GitBody_module_css_default.workstationLayout,
1224
+ style: { "--git-graph-col-width": `${graphColWidth}px` },
1225
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1226
+ className: GitBody_module_css_default.tablePane,
1227
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1228
+ className: GitBody_module_css_default.treeTableHeader,
1229
+ children: [
1230
+ (0, react_jsx_runtime.jsx)("span", {
1231
+ className: GitBody_module_css_default.colHeaderTitle,
1232
+ children: t("tree.colGraph")
1233
+ }),
1234
+ (0, react_jsx_runtime.jsx)("span", {
1235
+ className: GitBody_module_css_default.colHeaderTitle,
1236
+ children: t("tree.colSubject")
1237
+ }),
1238
+ (0, react_jsx_runtime.jsx)("span", {
1239
+ className: GitBody_module_css_default.colHeaderTitle,
1240
+ children: t("tree.colAuthor")
1241
+ }),
1242
+ (0, react_jsx_runtime.jsx)("span", {
1243
+ className: GitBody_module_css_default.colHeaderTitle,
1244
+ children: t("tree.colTime")
1245
+ }),
1246
+ (0, react_jsx_runtime.jsx)("span", {
1247
+ className: GitBody_module_css_default.colHeaderTitle,
1248
+ children: t("tree.colSha")
1249
+ })
1250
+ ]
1251
+ }), (0, react_jsx_runtime.jsxs)("div", {
1252
+ className: GitBody_module_css_default.treeContainer,
1253
+ style: { position: "relative" },
1254
+ children: [(0, react_jsx_runtime.jsxs)("svg", {
1255
+ className: GitBody_module_css_default.graphOverlaySvg,
1256
+ style: {
1257
+ width: `${graphColWidth}px`,
1258
+ height: `${filteredCommits.length * 28}px`
1259
+ },
1260
+ children: [dagGraph.edges.map((e) => (0, react_jsx_runtime.jsx)("path", {
1261
+ d: e.d,
1262
+ stroke: e.color,
1263
+ strokeWidth: 2,
1264
+ fill: "none",
1265
+ strokeLinecap: "round"
1266
+ }, e.key)), dagGraph.nodes.map((n) => {
1267
+ return (0, react_jsx_runtime.jsxs)("g", { children: [
1268
+ highlightedCommitHash === n.hash && (0, react_jsx_runtime.jsx)("circle", {
1269
+ cx: n.x,
1270
+ cy: n.y,
1271
+ r: 8.5,
1272
+ className: GitBody_module_css_default.locateGlowRing
1273
+ }),
1274
+ n.hasTag && (0, react_jsx_runtime.jsx)("circle", {
1275
+ cx: n.x,
1276
+ cy: n.y,
1277
+ r: 6.5,
1278
+ stroke: "#f0883e",
1279
+ strokeWidth: 1.5,
1280
+ fill: "none",
1281
+ opacity: .9
1282
+ }),
1283
+ n.isHead && !n.hasTag && (0, react_jsx_runtime.jsx)("circle", {
1284
+ cx: n.x,
1285
+ cy: n.y,
1286
+ r: 6.5,
1287
+ stroke: n.color,
1288
+ strokeWidth: 1.5,
1289
+ fill: "none",
1290
+ opacity: .8
1291
+ }),
1292
+ (0, react_jsx_runtime.jsx)("circle", {
1293
+ cx: n.x,
1294
+ cy: n.y,
1295
+ r: 4,
1296
+ fill: n.color
1297
+ })
1298
+ ] }, n.hash);
1299
+ })]
1300
+ }), filteredCommits.map((c) => {
1301
+ const isSelected = selectedCommitHash === c.hash;
1302
+ const isHighlighted = highlightedCommitHash === c.hash;
1303
+ const parsed = parseConventionalCommit(c.subject);
1304
+ const avatar = getAuthorAvatar(c.author);
1305
+ return (0, react_jsx_runtime.jsxs)("div", {
1306
+ id: `git-commit-${c.hash}`,
1307
+ className: [
1308
+ GitBody_module_css_default.treeRowGrid,
1309
+ isSelected ? GitBody_module_css_default.treeRowGridSelected : "",
1310
+ isHighlighted ? GitBody_module_css_default.treeRowHighlighted : ""
1311
+ ].filter(Boolean).join(" "),
1312
+ onClick: () => {
1313
+ handleSelectCommit(c.hash);
1314
+ },
1315
+ children: [
1316
+ (0, react_jsx_runtime.jsx)("div", { style: {
1317
+ width: `${graphColWidth}px`,
1318
+ height: 28,
1319
+ flexShrink: 0
1320
+ } }),
1321
+ (0, react_jsx_runtime.jsxs)("div", {
1322
+ className: GitBody_module_css_default.subjectCol,
1323
+ children: [
1324
+ c.refs?.map((ref, idx) => {
1325
+ let refClass = GitBody_module_css_default.refBranch;
1326
+ let refText = ref;
1327
+ if (ref.startsWith("tag: ")) {
1328
+ refClass = GitBody_module_css_default.refTag;
1329
+ refText = `🏷️ ${ref.slice(5)}`;
1330
+ } else if (ref.includes("HEAD")) refClass = GitBody_module_css_default.refHead;
1331
+ else if (ref.startsWith("origin/")) refClass = GitBody_module_css_default.refRemote;
1332
+ return (0, react_jsx_runtime.jsx)("span", {
1333
+ className: `${GitBody_module_css_default.refBadge} ${refClass}`,
1334
+ title: ref,
1335
+ children: refText
1336
+ }, idx);
1337
+ }),
1338
+ parsed.type && (0, react_jsx_runtime.jsx)("span", {
1339
+ className: `${GitBody_module_css_default.typeBadge} ${getTypeBadgeClass(parsed.type)}`,
1340
+ children: parsed.type
1341
+ }),
1342
+ (0, react_jsx_runtime.jsx)("span", {
1343
+ className: GitBody_module_css_default.treeSubject,
1344
+ title: c.subject,
1345
+ children: c.subject
1346
+ }),
1347
+ (0, react_jsx_runtime.jsxs)("div", {
1348
+ className: GitBody_module_css_default.treeRowActions,
1349
+ onClick: (e) => {
1350
+ e.stopPropagation();
1351
+ },
1352
+ children: [
1353
+ (0, react_jsx_runtime.jsx)("button", {
1354
+ type: "button",
1355
+ className: GitBody_module_css_default.treeActionBtn,
1356
+ title: "复制完整 SHA",
1357
+ onClick: () => {
1358
+ navigator.clipboard.writeText(c.hash);
1359
+ },
1360
+ children: "SHA"
1361
+ }),
1362
+ (0, react_jsx_runtime.jsx)("button", {
1363
+ type: "button",
1364
+ className: GitBody_module_css_default.treeActionBtn,
1365
+ title: "在此提交新建 Tag",
1366
+ onClick: () => {
1367
+ setNewTagCommit(c.shortHash);
1368
+ setCreatingTag(true);
1369
+ setActiveTab("tags");
1370
+ },
1371
+ children: "🏷️"
1372
+ }),
1373
+ (0, react_jsx_runtime.jsx)("button", {
1374
+ type: "button",
1375
+ className: GitBody_module_css_default.treeActionBtn,
1376
+ title: "在此提交新建分支",
1377
+ onClick: () => {
1378
+ setCreatingBranch(true);
1379
+ setActiveTab("branches");
1380
+ },
1381
+ children: "⑂"
1382
+ })
1383
+ ]
1384
+ })
1385
+ ]
1386
+ }),
1387
+ (0, react_jsx_runtime.jsxs)("div", {
1388
+ className: GitBody_module_css_default.authorCol,
1389
+ title: c.author,
1390
+ children: [(0, react_jsx_runtime.jsx)("span", {
1391
+ className: GitBody_module_css_default.authorAvatar,
1392
+ style: { background: avatar.color },
1393
+ children: avatar.initial
1394
+ }), (0, react_jsx_runtime.jsx)("span", {
1395
+ className: GitBody_module_css_default.authorNameText,
1396
+ children: c.author
1397
+ })]
1398
+ }),
1399
+ (0, react_jsx_runtime.jsx)("span", {
1400
+ className: GitBody_module_css_default.timeCol,
1401
+ title: c.date,
1402
+ children: c.relativeDate
1403
+ }),
1404
+ (0, react_jsx_runtime.jsx)("span", {
1405
+ className: GitBody_module_css_default.shaCol,
1406
+ title: c.hash,
1407
+ children: c.shortHash
1408
+ })
1409
+ ]
1410
+ }, c.hash);
1411
+ })]
1412
+ })]
1413
+ }), commitDetail && (0, react_jsx_runtime.jsxs)("div", {
1414
+ className: GitBody_module_css_default.detailsPane,
1415
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1416
+ className: GitBody_module_css_default.detailsHeader,
1417
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t("detail.title") }), (0, react_jsx_runtime.jsx)("button", {
1418
+ type: "button",
1419
+ className: GitBody_module_css_default.iconButton,
1420
+ title: "关闭详情",
1421
+ onClick: () => {
1422
+ setSelectedCommitHash(null);
1423
+ setCommitDetail(null);
1424
+ },
1425
+ children: "✕"
1426
+ })]
1427
+ }), (0, react_jsx_runtime.jsxs)("div", {
1428
+ className: GitBody_module_css_default.detailsContent,
1429
+ children: [
1430
+ (0, react_jsx_runtime.jsx)("div", {
1431
+ className: GitBody_module_css_default.detailsSubject,
1432
+ children: commitDetail.commit.subject
1433
+ }),
1434
+ commitDetail.body && (0, react_jsx_runtime.jsx)("div", {
1435
+ className: GitBody_module_css_default.detailsBody,
1436
+ children: commitDetail.body
1437
+ }),
1438
+ commitDetail.commit.refs && commitDetail.commit.refs.length > 0 && (0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsx)("div", {
1439
+ className: GitBody_module_css_default.detailsSectionTitle,
1440
+ children: t("detail.references")
1441
+ }), (0, react_jsx_runtime.jsx)("div", {
1442
+ style: {
1443
+ display: "flex",
1444
+ flexWrap: "wrap",
1445
+ gap: "4px"
1446
+ },
1447
+ children: commitDetail.commit.refs.map((ref, idx) => {
1448
+ let refClass = GitBody_module_css_default.refBranch;
1449
+ let refText = ref;
1450
+ if (ref.startsWith("tag: ")) {
1451
+ refClass = GitBody_module_css_default.refTag;
1452
+ refText = `🏷️ ${ref.slice(5)}`;
1453
+ } else if (ref.includes("HEAD")) refClass = GitBody_module_css_default.refHead;
1454
+ else if (ref.startsWith("origin/")) refClass = GitBody_module_css_default.refRemote;
1455
+ return (0, react_jsx_runtime.jsx)("span", {
1456
+ className: `${GitBody_module_css_default.refBadge} ${refClass}`,
1457
+ children: refText
1458
+ }, idx);
1459
+ })
1460
+ })] }),
1461
+ (0, react_jsx_runtime.jsxs)("div", {
1462
+ className: GitBody_module_css_default.detailsMetaGrid,
1463
+ children: [
1464
+ (0, react_jsx_runtime.jsxs)("div", {
1465
+ className: GitBody_module_css_default.detailsMetaRow,
1466
+ children: [(0, react_jsx_runtime.jsx)("span", {
1467
+ className: GitBody_module_css_default.detailsMetaLabel,
1468
+ children: t("detail.author")
1469
+ }), (0, react_jsx_runtime.jsx)("span", {
1470
+ className: GitBody_module_css_default.authorCol,
1471
+ style: { maxWidth: "180px" },
1472
+ children: (() => {
1473
+ const av = getAuthorAvatar(commitDetail.commit.author);
1474
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
1475
+ className: GitBody_module_css_default.authorAvatar,
1476
+ style: { background: av.color },
1477
+ children: av.initial
1478
+ }), (0, react_jsx_runtime.jsx)("span", {
1479
+ className: GitBody_module_css_default.authorNameText,
1480
+ children: commitDetail.commit.author
1481
+ })] });
1482
+ })()
1483
+ })]
1484
+ }),
1485
+ (0, react_jsx_runtime.jsxs)("div", {
1486
+ className: GitBody_module_css_default.detailsMetaRow,
1487
+ children: [(0, react_jsx_runtime.jsx)("span", {
1488
+ className: GitBody_module_css_default.detailsMetaLabel,
1489
+ children: t("detail.date")
1490
+ }), (0, react_jsx_runtime.jsx)("span", {
1491
+ className: GitBody_module_css_default.detailsMetaVal,
1492
+ children: formatFullDate(commitDetail.commit.date)
1493
+ })]
1494
+ }),
1495
+ (0, react_jsx_runtime.jsxs)("div", {
1496
+ className: GitBody_module_css_default.detailsMetaRow,
1497
+ children: [(0, react_jsx_runtime.jsx)("span", {
1498
+ className: GitBody_module_css_default.detailsMetaLabel,
1499
+ children: "Commit SHA"
1500
+ }), (0, react_jsx_runtime.jsx)("span", {
1501
+ className: GitBody_module_css_default.tagShaPill,
1502
+ title: "点击复制完整 SHA",
1503
+ onClick: () => {
1504
+ navigator.clipboard.writeText(commitDetail.commit.hash);
1505
+ },
1506
+ children: commitDetail.commit.hash.slice(0, 13)
1507
+ })]
1508
+ }),
1509
+ commitDetail.parents && commitDetail.parents.length > 0 && (0, react_jsx_runtime.jsxs)("div", {
1510
+ className: GitBody_module_css_default.detailsMetaRow,
1511
+ children: [(0, react_jsx_runtime.jsx)("span", {
1512
+ className: GitBody_module_css_default.detailsMetaLabel,
1513
+ children: t("detail.parent")
1514
+ }), (0, react_jsx_runtime.jsx)("div", {
1515
+ style: {
1516
+ display: "flex",
1517
+ gap: "4px"
1518
+ },
1519
+ children: commitDetail.parents.map((p) => (0, react_jsx_runtime.jsx)("span", {
1520
+ className: GitBody_module_css_default.detailsParentLink,
1521
+ title: `定位到父提交: ${p}`,
1522
+ onClick: () => {
1523
+ handleLocateCommit(p);
1524
+ },
1525
+ children: p.slice(0, 10)
1526
+ }, p))
1527
+ })]
1528
+ })
1529
+ ]
1530
+ }),
1531
+ (0, react_jsx_runtime.jsxs)("div", { children: [(0, react_jsx_runtime.jsxs)("div", {
1532
+ style: {
1533
+ display: "flex",
1534
+ justifyContent: "space-between",
1535
+ alignItems: "center",
1536
+ marginBottom: "6px"
1537
+ },
1538
+ children: [(0, react_jsx_runtime.jsxs)("span", {
1539
+ style: {
1540
+ fontSize: "11px",
1541
+ fontWeight: 600
1542
+ },
1543
+ children: [
1544
+ "变更文件 (",
1545
+ commitDetail.files.length,
1546
+ " 个文件)"
1547
+ ]
1548
+ }), (0, react_jsx_runtime.jsxs)("span", {
1549
+ className: GitBody_module_css_default.numstat,
1550
+ children: [(0, react_jsx_runtime.jsxs)("span", {
1551
+ className: GitBody_module_css_default.addStat,
1552
+ children: ["+", commitDetail.totalAdditions]
1553
+ }), (0, react_jsx_runtime.jsxs)("span", {
1554
+ className: GitBody_module_css_default.delStat,
1555
+ children: ["-", commitDetail.totalDeletions]
1556
+ })]
1557
+ })]
1558
+ }), (0, react_jsx_runtime.jsx)("div", {
1559
+ className: GitBody_module_css_default.detailFilesList,
1560
+ children: commitDetail.files.map((f) => (0, react_jsx_runtime.jsxs)("div", {
1561
+ className: GitBody_module_css_default.detailFileItem,
1562
+ onClick: () => {
1563
+ handleViewDiff(f.path, false, commitDetail.commit.hash);
1564
+ },
1565
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1566
+ className: GitBody_module_css_default.fileLeft,
1567
+ children: [(0, react_jsx_runtime.jsx)("span", {
1568
+ className: `${GitBody_module_css_default.statusBadge} ${f.status === "added" ? GitBody_module_css_default.statusA : f.status === "deleted" ? GitBody_module_css_default.statusD : GitBody_module_css_default.statusM}`,
1569
+ children: f.status[0]?.toUpperCase() ?? "M"
1570
+ }), (0, react_jsx_runtime.jsx)("span", {
1571
+ className: GitBody_module_css_default.fileName,
1572
+ children: f.path
1573
+ })]
1574
+ }), (0, react_jsx_runtime.jsxs)("span", {
1575
+ className: GitBody_module_css_default.numstat,
1576
+ children: [(0, react_jsx_runtime.jsxs)("span", {
1577
+ className: GitBody_module_css_default.addStat,
1578
+ children: ["+", f.additions]
1579
+ }), (0, react_jsx_runtime.jsxs)("span", {
1580
+ className: GitBody_module_css_default.delStat,
1581
+ children: ["-", f.deletions]
1582
+ })]
1583
+ })]
1584
+ }, f.path))
1585
+ })] }),
1586
+ selectedFileDiff && (0, react_jsx_runtime.jsxs)("div", {
1587
+ style: { marginTop: "6px" },
1588
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1589
+ style: {
1590
+ display: "flex",
1591
+ justifyContent: "space-between",
1592
+ alignItems: "center",
1593
+ marginBottom: "4px"
1594
+ },
1595
+ children: [(0, react_jsx_runtime.jsxs)("span", {
1596
+ style: {
1597
+ fontSize: "11px",
1598
+ fontWeight: 600
1599
+ },
1600
+ children: ["差异: ", selectedFileDiff.path]
1601
+ }), (0, react_jsx_runtime.jsx)("button", {
1602
+ type: "button",
1603
+ className: GitBody_module_css_default.actionTextBtn,
1604
+ onClick: () => {
1605
+ setSelectedFileDiff(null);
1606
+ },
1607
+ children: "关闭"
1608
+ })]
1609
+ }), (0, react_jsx_runtime.jsx)(DiffViewer, { diffText: selectedFileDiff.diff })]
1610
+ }),
1611
+ (0, react_jsx_runtime.jsxs)("div", {
1612
+ className: GitBody_module_css_default.detailsBottomActions,
1613
+ children: [(0, react_jsx_runtime.jsx)("button", {
1614
+ type: "button",
1615
+ className: GitBody_module_css_default.actionTextBtn,
1616
+ style: {
1617
+ flex: 1,
1618
+ padding: "5px"
1619
+ },
1620
+ onClick: () => {
1621
+ handleCheckoutBranch(commitDetail.commit.shortHash);
1622
+ },
1623
+ children: t("detail.checkout")
1624
+ }), (0, react_jsx_runtime.jsx)("button", {
1625
+ type: "button",
1626
+ className: GitBody_module_css_default.commitBtn,
1627
+ style: {
1628
+ flex: 1,
1629
+ padding: "5px"
1630
+ },
1631
+ onClick: () => {
1632
+ setNewTagCommit(commitDetail.commit.shortHash);
1633
+ setCreatingTag(true);
1634
+ setActiveTab("tags");
1635
+ },
1636
+ children: t("detail.createBranchOrTag")
1637
+ })]
1638
+ })
1639
+ ]
1640
+ })]
1641
+ })]
1642
+ }),
1643
+ (0, react_jsx_runtime.jsxs)("div", {
1644
+ className: GitBody_module_css_default.treeStatusFooter,
1645
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1646
+ className: GitBody_module_css_default.footerSyncStatus,
1647
+ children: [(0, react_jsx_runtime.jsx)("span", { className: GitBody_module_css_default.syncDot }), (0, react_jsx_runtime.jsx)("span", { children: status.ahead === 0 && status.behind === 0 ? t("footer.syncNormal") : status.ahead > 0 ? t("footer.ahead", { count: status.ahead }) : t("footer.behind", { count: status.behind }) })]
1648
+ }), (0, react_jsx_runtime.jsxs)("div", {
1649
+ className: GitBody_module_css_default.footerStats,
1650
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t("footer.showingCount", {
1651
+ count: filteredCommits.length,
1652
+ total: status.totalCommitsCount ?? commits.length
1653
+ }) }), status.totalCommitsCount && commits.length < status.totalCommitsCount && (0, react_jsx_runtime.jsx)("span", {
1654
+ className: GitBody_module_css_default.loadMoreLink,
1655
+ onClick: () => {
1656
+ handleLoadMore();
1657
+ },
1658
+ children: t("footer.loadMore")
1659
+ })]
1660
+ })]
1661
+ })
1662
+ ]
1663
+ }),
1664
+ activeTab === "branches" && (0, react_jsx_runtime.jsxs)("div", {
1665
+ style: {
1666
+ display: "flex",
1667
+ flexDirection: "column",
1668
+ gap: "8px"
1669
+ },
1670
+ children: [
1671
+ (0, react_jsx_runtime.jsxs)("div", {
1672
+ style: {
1673
+ display: "flex",
1674
+ gap: "6px"
1675
+ },
1676
+ children: [(0, react_jsx_runtime.jsx)("input", {
1677
+ className: GitBody_module_css_default.commitTextarea,
1678
+ style: {
1679
+ minHeight: "30px",
1680
+ height: "30px",
1681
+ padding: "4px 8px"
1682
+ },
1683
+ placeholder: t("branch.filter"),
1684
+ value: branchFilter,
1685
+ onChange: (e) => {
1686
+ setBranchFilter(e.target.value);
1687
+ }
1688
+ }), (0, react_jsx_runtime.jsx)("button", {
1689
+ type: "button",
1690
+ className: GitBody_module_css_default.actionTextBtn,
1691
+ style: { flexShrink: 0 },
1692
+ onClick: () => {
1693
+ setCreatingBranch((prev) => !prev);
1694
+ },
1695
+ children: "+ 新建分支"
1696
+ })]
1697
+ }),
1698
+ creatingBranch && (0, react_jsx_runtime.jsxs)("div", {
1699
+ style: {
1700
+ display: "flex",
1701
+ gap: "6px"
1702
+ },
1703
+ children: [(0, react_jsx_runtime.jsx)("input", {
1704
+ autoFocus: true,
1705
+ className: GitBody_module_css_default.commitTextarea,
1706
+ style: {
1707
+ minHeight: "30px",
1708
+ height: "30px",
1709
+ padding: "4px 8px"
1710
+ },
1711
+ placeholder: "新分支名称...",
1712
+ value: newBranchName,
1713
+ onChange: (e) => {
1714
+ setNewBranchName(e.target.value);
1715
+ },
1716
+ onKeyDown: (e) => {
1717
+ if (e.key === "Enter") {
1718
+ const trimmed = newBranchName.trim();
1719
+ if (trimmed) handleCheckoutBranch(trimmed, true);
1720
+ }
1721
+ }
1722
+ }), (0, react_jsx_runtime.jsx)("button", {
1723
+ type: "button",
1724
+ className: GitBody_module_css_default.commitBtn,
1725
+ onClick: () => {
1726
+ const trimmed = newBranchName.trim();
1727
+ if (trimmed) handleCheckoutBranch(trimmed, true);
1728
+ },
1729
+ children: "创建并检出"
1730
+ })]
1731
+ }),
1732
+ (0, react_jsx_runtime.jsxs)("div", {
1733
+ className: GitBody_module_css_default.section,
1734
+ children: [(0, react_jsx_runtime.jsx)("div", {
1735
+ className: GitBody_module_css_default.sectionHeader,
1736
+ children: (0, react_jsx_runtime.jsxs)("span", { children: [
1737
+ "本地分支 (",
1738
+ filteredLocalBranches.length,
1739
+ ")"
1740
+ ] })
1741
+ }), (0, react_jsx_runtime.jsx)("div", {
1742
+ className: GitBody_module_css_default.fileList,
1743
+ children: filteredLocalBranches.map((b) => (0, react_jsx_runtime.jsxs)("div", {
1744
+ className: GitBody_module_css_default.fileItem,
1745
+ style: { background: b.isCurrent ? "rgba(56, 139, 253, 0.15)" : void 0 },
1746
+ onClick: () => {
1747
+ if (!b.isCurrent) handleCheckoutBranch(b.name);
1748
+ },
1749
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1750
+ className: GitBody_module_css_default.fileLeft,
1751
+ children: [(0, react_jsx_runtime.jsx)("span", {
1752
+ style: { color: b.isCurrent ? "#388bfd" : "inherit" },
1753
+ children: b.isCurrent ? "●" : "○"
1754
+ }), (0, react_jsx_runtime.jsx)("span", {
1755
+ style: { fontWeight: b.isCurrent ? 600 : 400 },
1756
+ children: b.name
1757
+ })]
1758
+ }), b.isCurrent && (0, react_jsx_runtime.jsx)("span", {
1759
+ style: {
1760
+ fontSize: "11px",
1761
+ color: "#58a6ff"
1762
+ },
1763
+ children: "当前检出"
1764
+ })]
1765
+ }, b.name))
1766
+ })]
1767
+ }),
1768
+ filteredRemoteBranches.length > 0 && (0, react_jsx_runtime.jsxs)("div", {
1769
+ className: GitBody_module_css_default.section,
1770
+ children: [(0, react_jsx_runtime.jsx)("div", {
1771
+ className: GitBody_module_css_default.sectionHeader,
1772
+ children: (0, react_jsx_runtime.jsxs)("span", { children: [
1773
+ "远程分支 (",
1774
+ filteredRemoteBranches.length,
1775
+ ")"
1776
+ ] })
1777
+ }), (0, react_jsx_runtime.jsx)("div", {
1778
+ className: GitBody_module_css_default.fileList,
1779
+ children: filteredRemoteBranches.map((b) => (0, react_jsx_runtime.jsx)("div", {
1780
+ className: GitBody_module_css_default.fileItem,
1781
+ onClick: () => {
1782
+ handleCheckoutBranch(b.name);
1783
+ },
1784
+ children: (0, react_jsx_runtime.jsxs)("div", {
1785
+ className: GitBody_module_css_default.fileLeft,
1786
+ children: [(0, react_jsx_runtime.jsx)("span", {
1787
+ style: { opacity: .6 },
1788
+ children: "☁"
1789
+ }), (0, react_jsx_runtime.jsx)("span", { children: b.name })]
1790
+ })
1791
+ }, b.name))
1792
+ })]
1793
+ })
1794
+ ]
1795
+ }),
1796
+ activeTab === "tags" && (0, react_jsx_runtime.jsxs)("div", {
1797
+ style: {
1798
+ display: "flex",
1799
+ flexDirection: "column",
1800
+ gap: "8px"
1801
+ },
1802
+ children: [
1803
+ (0, react_jsx_runtime.jsxs)("div", {
1804
+ style: {
1805
+ display: "flex",
1806
+ gap: "6px"
1807
+ },
1808
+ children: [(0, react_jsx_runtime.jsx)("input", {
1809
+ className: GitBody_module_css_default.commitTextarea,
1810
+ style: {
1811
+ minHeight: "30px",
1812
+ height: "30px",
1813
+ padding: "4px 8px"
1814
+ },
1815
+ placeholder: t("tag.filter"),
1816
+ value: tagFilter,
1817
+ onChange: (e) => {
1818
+ setTagFilter(e.target.value);
1819
+ }
1820
+ }), (0, react_jsx_runtime.jsxs)("button", {
1821
+ type: "button",
1822
+ className: GitBody_module_css_default.actionTextBtn,
1823
+ style: { flexShrink: 0 },
1824
+ onClick: () => {
1825
+ setCreatingTag((prev) => !prev);
1826
+ },
1827
+ children: ["+ ", t("tag.newPrompt")]
1828
+ })]
1829
+ }),
1830
+ creatingTag && (0, react_jsx_runtime.jsxs)("div", {
1831
+ className: GitBody_module_css_default.tagForm,
1832
+ children: [
1833
+ (0, react_jsx_runtime.jsx)("div", {
1834
+ className: GitBody_module_css_default.tagFormTitle,
1835
+ children: t("tag.newPrompt")
1836
+ }),
1837
+ (0, react_jsx_runtime.jsxs)("div", {
1838
+ style: {
1839
+ display: "flex",
1840
+ flexDirection: "column",
1841
+ gap: "4px"
1842
+ },
1843
+ children: [(0, react_jsx_runtime.jsxs)("label", {
1844
+ style: {
1845
+ fontSize: "11px",
1846
+ color: "var(--dsw-alias-label-secondary)"
1847
+ },
1848
+ children: [t("tag.nameLabel"), " *"]
1849
+ }), (0, react_jsx_runtime.jsx)("input", {
1850
+ autoFocus: true,
1851
+ className: GitBody_module_css_default.commitTextarea,
1852
+ style: {
1853
+ minHeight: "28px",
1854
+ height: "28px",
1855
+ padding: "4px 8px"
1856
+ },
1857
+ placeholder: t("tag.namePlaceholder"),
1858
+ value: newTagName,
1859
+ onChange: (e) => {
1860
+ setNewTagName(e.target.value);
1861
+ }
1862
+ })]
1863
+ }),
1864
+ (0, react_jsx_runtime.jsxs)("div", {
1865
+ style: {
1866
+ display: "flex",
1867
+ flexDirection: "column",
1868
+ gap: "4px"
1869
+ },
1870
+ children: [(0, react_jsx_runtime.jsx)("label", {
1871
+ style: {
1872
+ fontSize: "11px",
1873
+ color: "var(--dsw-alias-label-secondary)"
1874
+ },
1875
+ children: t("tag.targetCommitLabel")
1876
+ }), (0, react_jsx_runtime.jsx)("input", {
1877
+ className: GitBody_module_css_default.commitTextarea,
1878
+ style: {
1879
+ minHeight: "28px",
1880
+ height: "28px",
1881
+ padding: "4px 8px"
1882
+ },
1883
+ placeholder: "例如 687f282 或留空为 HEAD",
1884
+ value: newTagCommit,
1885
+ onChange: (e) => {
1886
+ setNewTagCommit(e.target.value);
1887
+ }
1888
+ })]
1889
+ }),
1890
+ (0, react_jsx_runtime.jsxs)("div", {
1891
+ style: {
1892
+ display: "flex",
1893
+ flexDirection: "column",
1894
+ gap: "4px"
1895
+ },
1896
+ children: [(0, react_jsx_runtime.jsx)("label", {
1897
+ style: {
1898
+ fontSize: "11px",
1899
+ color: "var(--dsw-alias-label-secondary)"
1900
+ },
1901
+ children: t("tag.messageLabel")
1902
+ }), (0, react_jsx_runtime.jsx)("input", {
1903
+ className: GitBody_module_css_default.commitTextarea,
1904
+ style: {
1905
+ minHeight: "28px",
1906
+ height: "28px",
1907
+ padding: "4px 8px"
1908
+ },
1909
+ placeholder: t("tag.messagePrompt"),
1910
+ value: newTagMessage,
1911
+ onChange: (e) => {
1912
+ setNewTagMessage(e.target.value);
1913
+ }
1914
+ })]
1915
+ }),
1916
+ (0, react_jsx_runtime.jsxs)("div", {
1917
+ className: GitBody_module_css_default.tagFormActions,
1918
+ children: [(0, react_jsx_runtime.jsx)("button", {
1919
+ type: "button",
1920
+ className: GitBody_module_css_default.actionTextBtn,
1921
+ onClick: () => {
1922
+ setCreatingTag(false);
1923
+ },
1924
+ children: t("tag.cancelBtn")
1925
+ }), (0, react_jsx_runtime.jsx)("button", {
1926
+ type: "button",
1927
+ className: GitBody_module_css_default.commitBtn,
1928
+ onClick: () => {
1929
+ handleCreateTag();
1930
+ },
1931
+ children: t("tag.createBtn")
1932
+ })]
1933
+ })
1934
+ ]
1935
+ }),
1936
+ filteredTags.length === 0 ? (0, react_jsx_runtime.jsxs)("div", {
1937
+ className: GitBody_module_css_default.emptyState,
1938
+ children: [(0, react_jsx_runtime.jsx)("svg", {
1939
+ viewBox: "0 0 16 16",
1940
+ fill: "currentColor",
1941
+ children: (0, react_jsx_runtime.jsx)("path", { d: "M1 7.775V2.75C1 1.784 1.784 1 2.75 1h5.025c.464 0 .91.184 1.238.513l6.25 6.25a1.75 1.75 0 0 1 0 2.474l-5.026 5.026a1.75 1.75 0 0 1-2.474 0l-6.25-6.25A1.752 1.752 0 0 1 1 7.775zm1.5 0c0 .066.026.13.073.177l6.25 6.25a.25.25 0 0 0 .354 0l5.025-5.025a.25.25 0 0 0 0-.354l-6.25-6.25a.25.25 0 0 0-.177-.073H2.75a.25.25 0 0 0-.25.25v5.025zM6 4.5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z" })
1942
+ }), (0, react_jsx_runtime.jsx)("div", { children: t("tag.empty") })]
1943
+ }) : (0, react_jsx_runtime.jsx)("div", {
1944
+ className: GitBody_module_css_default.tagList,
1945
+ children: filteredTags.map((tag) => (0, react_jsx_runtime.jsxs)("div", {
1946
+ className: GitBody_module_css_default.tagCard,
1947
+ children: [
1948
+ (0, react_jsx_runtime.jsxs)("div", {
1949
+ className: GitBody_module_css_default.tagCardHeader,
1950
+ children: [(0, react_jsx_runtime.jsxs)("div", {
1951
+ className: GitBody_module_css_default.tagTitleRow,
1952
+ children: [
1953
+ (0, react_jsx_runtime.jsx)("span", {
1954
+ style: { fontSize: "13px" },
1955
+ children: "🏷️"
1956
+ }),
1957
+ (0, react_jsx_runtime.jsx)("span", {
1958
+ className: GitBody_module_css_default.tagName,
1959
+ title: "点击在图谱中定位",
1960
+ onClick: () => {
1961
+ handleLocateCommit(tag.commitHash, tag.name);
1962
+ },
1963
+ children: tag.name
1964
+ }),
1965
+ (0, react_jsx_runtime.jsx)("span", {
1966
+ className: GitBody_module_css_default.tagShaPill,
1967
+ title: `Commit: ${tag.commitHash} (点击在图谱中定位)`,
1968
+ onClick: () => {
1969
+ handleLocateCommit(tag.commitHash, tag.name);
1970
+ },
1971
+ children: tag.shortHash
1972
+ }),
1973
+ tag.isAnnotated && (0, react_jsx_runtime.jsx)("span", {
1974
+ className: GitBody_module_css_default.tagAnnotatedBadge,
1975
+ children: t("tag.annotated")
1976
+ })
1977
+ ]
1978
+ }), (0, react_jsx_runtime.jsxs)("div", {
1979
+ className: GitBody_module_css_default.tagActions,
1980
+ children: [
1981
+ (0, react_jsx_runtime.jsxs)("button", {
1982
+ type: "button",
1983
+ className: GitBody_module_css_default.tagLocateBtn,
1984
+ title: "在图谱中定位该提交",
1985
+ onClick: () => {
1986
+ handleLocateCommit(tag.commitHash, tag.name);
1987
+ },
1988
+ children: [(0, react_jsx_runtime.jsx)("span", { children: "🎯" }), (0, react_jsx_runtime.jsx)("span", { children: t("tag.locateBtn") })]
1989
+ }),
1990
+ (0, react_jsx_runtime.jsx)("button", {
1991
+ type: "button",
1992
+ className: GitBody_module_css_default.fileMiniBtn,
1993
+ title: t("tag.copyName"),
1994
+ onClick: () => {
1995
+ navigator.clipboard.writeText(tag.name);
1996
+ },
1997
+ children: "📋"
1998
+ }),
1999
+ (0, react_jsx_runtime.jsx)("button", {
2000
+ type: "button",
2001
+ className: GitBody_module_css_default.fileMiniBtn,
2002
+ title: t("tag.deleteBtn"),
2003
+ onClick: () => {
2004
+ handleDeleteTag(tag.name);
2005
+ },
2006
+ children: "🗑️"
2007
+ })
2008
+ ]
2009
+ })]
2010
+ }),
2011
+ tag.message && (0, react_jsx_runtime.jsx)("div", {
2012
+ className: GitBody_module_css_default.tagMessage,
2013
+ title: tag.message,
2014
+ children: tag.message
2015
+ }),
2016
+ (0, react_jsx_runtime.jsxs)("div", {
2017
+ className: GitBody_module_css_default.tagMetaFooter,
2018
+ children: [(0, react_jsx_runtime.jsxs)("span", {
2019
+ className: GitBody_module_css_default.tagAuthor,
2020
+ children: [(0, react_jsx_runtime.jsx)("span", { children: "👤" }), (0, react_jsx_runtime.jsx)("span", { children: tag.author })]
2021
+ }), (0, react_jsx_runtime.jsx)("span", {
2022
+ title: tag.date,
2023
+ children: tag.relativeDate
2024
+ })]
2025
+ })
2026
+ ]
2027
+ }, tag.name))
2028
+ })
2029
+ ]
2030
+ })
2031
+ ]
2032
+ })
2033
+ ]
2034
+ });
2035
+ });
2036
+ //#endregion
2037
+ //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/experimental/git/src/client/GitBranchPill.module.css.mjs
2038
+ const css = ".F_1oUa_anchor{min-width:0;font-size:calc(var(--dsh-content-font-size-secondary,13px) - 1px);line-height:calc(20px + var(--dsh-content-font-delta-secondary,0px));display:inline-flex;position:relative}.F_1oUa_pill{box-sizing:border-box;border-radius:var(--dsw-radius-sm);max-width:100%;color:var(--dsw-alias-label-tertiary);font:inherit;font-variant-numeric:tabular-nums;font-weight:500;line-height:inherit;white-space:nowrap;cursor:pointer;background:0 0;border:none;align-items:center;gap:6px;padding:1px 8px;transition:background .15s,color .15s;display:inline-flex}.F_1oUa_pill:hover,.F_1oUa_pill[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F_1oUa_icon{width:14px;height:14px;color:var(--dsw-alias-label-tertiary);flex:none}.F_1oUa_pill:hover .F_1oUa_icon,.F_1oUa_pill[aria-expanded=true] .F_1oUa_icon{color:var(--dsw-alias-state-business-primary)}.F_1oUa_branchName{text-overflow:ellipsis;white-space:nowrap;max-width:150px;overflow:hidden}.F_1oUa_badge{border-radius:var(--dsw-radius-xs,3px);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);align-items:center;padding:0 4px;font-size:11px;font-weight:500;line-height:14px;display:inline-flex}.F_1oUa_badgeAhead{color:var(--dsw-alias-state-business-primary)}.F_1oUa_badgeBehind{color:var(--dsw-alias-state-warn-primary)}.F_1oUa_popover{z-index:1100;box-sizing:border-box;border-radius:var(--dsw-radius-lg);--dsw-elevation-stroke-color:var(--dsw-alias-border-l1);width:310px;max-height:440px;box-shadow:var(--dsw-elevation-prominent);color:var(--dsw-alias-label-primary);cursor:default;border:0;flex-direction:column;font-size:12px;line-height:18px;animation:.15s cubic-bezier(.16,1,.3,1) F_1oUa_popoverFadeIn;display:flex;position:fixed;overflow:hidden}@keyframes F_1oUa_popoverFadeIn{0%{opacity:0;transform:translateY(4px)scale(.98)}to{opacity:1;transform:translateY(0)scale(1)}}.F_1oUa_header{border-bottom:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:6px;padding:8px 10px 6px;display:flex}.F_1oUa_searchRow{border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-interactive-bg-hover);border:.5px solid var(--dsw-alias-border-l2);align-items:center;gap:6px;padding:4px 8px;display:flex}.F_1oUa_searchIcon{width:13px;height:13px;color:var(--dsw-alias-label-tertiary);flex:none}.F_1oUa_searchInput{color:var(--dsw-alias-label-primary);background:0 0;border:none;outline:none;flex:1;font-size:12px}.F_1oUa_searchInput::placeholder{color:var(--dsw-alias-label-tertiary)}.F_1oUa_actionBar{justify-content:space-between;align-items:center;gap:4px;display:flex}.F_1oUa_toolBtnGroup{align-items:center;gap:4px;display:flex}.F_1oUa_toolBtn{border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-sm);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:4px;padding:3px 8px;font-family:inherit;font-size:11px;font-weight:500;transition:background .15s,color .15s;display:inline-flex}.F_1oUa_toolBtn:hover{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary)}.F_1oUa_btnIcon{flex:none;width:12px;height:12px}.F_1oUa_newBranchBox{gap:6px;margin-top:2px;display:flex}.F_1oUa_newBranchInput{border-radius:var(--dsw-radius-sm);border:.5px solid var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);outline:none;flex:1;padding:4px 8px;font-size:12px}.F_1oUa_newBranchInput::placeholder{color:var(--dsw-alias-label-tertiary)}.F_1oUa_branchList{flex:1;padding:4px;overflow-y:auto}.F_1oUa_groupLabel{color:var(--dsw-alias-label-tertiary);align-items:center;gap:6px;padding:6px 8px 3px;font-size:11px;font-weight:500;display:flex}.F_1oUa_branchItem{border-radius:var(--dsw-radius-sm);width:100%;color:var(--dsw-alias-label-secondary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;justify-content:space-between;align-items:center;padding:5px 8px;font-size:12px;transition:background .12s,color .12s;display:flex}.F_1oUa_branchItem:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F_1oUa_currentBranch{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-state-business-primary);font-weight:500}.F_1oUa_currentBranch:hover{background:var(--dsw-alias-interactive-bg-active)}.F_1oUa_branchItemLeft{flex:1;align-items:center;gap:6px;min-width:0;display:flex}.F_1oUa_itemIcon{width:13px;height:13px;color:var(--dsw-alias-label-tertiary);flex:none}.F_1oUa_currentBranch .F_1oUa_itemIcon{color:var(--dsw-alias-state-business-primary)}.F_1oUa_itemText{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F_1oUa_checkMark{width:14px;height:14px;color:var(--dsw-alias-state-business-primary);flex:none}.F_1oUa_emptyTip{text-align:center;color:var(--dsw-alias-label-tertiary);padding:16px 8px;font-size:12px}";
2039
+ const tagId = "@civilization/dsh-experimental-git/GitBranchPill.module.css";
2040
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
2041
+ const tag = document.createElement("style");
2042
+ tag.dataset.plugin = "@civilization/dsh-experimental-git";
2043
+ tag.dataset.pluginCss = tagId;
2044
+ tag.textContent = css;
2045
+ document.head.appendChild(tag);
2046
+ }
2047
+ var GitBranchPill_module_css_default = {
2048
+ "actionBar": "F_1oUa_actionBar",
2049
+ "anchor": "F_1oUa_anchor",
2050
+ "badge": "F_1oUa_badge",
2051
+ "badgeAhead": "F_1oUa_badgeAhead",
2052
+ "badgeBehind": "F_1oUa_badgeBehind",
2053
+ "branchItem": "F_1oUa_branchItem",
2054
+ "branchItemLeft": "F_1oUa_branchItemLeft",
2055
+ "branchList": "F_1oUa_branchList",
2056
+ "branchName": "F_1oUa_branchName",
2057
+ "btnIcon": "F_1oUa_btnIcon",
2058
+ "checkMark": "F_1oUa_checkMark",
2059
+ "currentBranch": "F_1oUa_currentBranch",
2060
+ "emptyTip": "F_1oUa_emptyTip",
2061
+ "groupLabel": "F_1oUa_groupLabel",
2062
+ "header": "F_1oUa_header",
2063
+ "icon": "F_1oUa_icon",
2064
+ "itemIcon": "F_1oUa_itemIcon",
2065
+ "itemText": "F_1oUa_itemText",
2066
+ "newBranchBox": "F_1oUa_newBranchBox",
2067
+ "newBranchInput": "F_1oUa_newBranchInput",
2068
+ "pill": "F_1oUa_pill",
2069
+ "popover": "F_1oUa_popover",
2070
+ "popoverFadeIn": "F_1oUa_popoverFadeIn",
2071
+ "searchIcon": "F_1oUa_searchIcon",
2072
+ "searchInput": "F_1oUa_searchInput",
2073
+ "searchRow": "F_1oUa_searchRow",
2074
+ "toolBtn": "F_1oUa_toolBtn",
2075
+ "toolBtnGroup": "F_1oUa_toolBtnGroup"
2076
+ };
2077
+ //#endregion
2078
+ //#region lib/types/client/GitBranchPill.js
2079
+ /**
2080
+ * Status bar Git branch pill and popover branch switcher (IDEA / VS Code style).
2081
+ * Injected into the 'conversation.composer.dock' slot at order: -1.
2082
+ */
2083
+ /**
2084
+ * Git Branch Pill rendered in the Composer Dock.
2085
+ */
2086
+ const GitBranchPill = (0, react.memo)(function GitBranchPill({ getStatus, getBranches, checkout, pull, push, sessionId }) {
2087
+ const [status, setStatus] = (0, react.useState)(null);
2088
+ const [branches, setBranches] = (0, react.useState)(null);
2089
+ const [open, setOpen] = (0, react.useState)(false);
2090
+ const [filter, setFilter] = (0, react.useState)("");
2091
+ const [creatingBranch, setCreatingBranch] = (0, react.useState)(false);
2092
+ const [newBranchName, setNewBranchName] = (0, react.useState)("");
2093
+ const [switching, setSwitching] = (0, react.useState)(false);
2094
+ const anchorRef = (0, react.useRef)(null);
2095
+ const popoverRef = (0, react.useRef)(null);
2096
+ const [popoverPos, setPopoverPos] = (0, react.useState)(null);
2097
+ const refresh = (0, react.useCallback)(async () => {
2098
+ if (!getStatus || !getBranches) return;
2099
+ try {
2100
+ const [statusRes, branchRes] = await Promise.all([getStatus(sessionId), getBranches(sessionId)]);
2101
+ setStatus(statusRes);
2102
+ setBranches(branchRes);
2103
+ } catch {}
2104
+ }, [
2105
+ getStatus,
2106
+ getBranches,
2107
+ sessionId
2108
+ ]);
2109
+ (0, react.useEffect)(() => {
2110
+ refresh();
2111
+ const timer = setInterval(() => {
2112
+ refresh();
2113
+ }, 5e3);
2114
+ return () => {
2115
+ clearInterval(timer);
2116
+ };
2117
+ }, [refresh]);
2118
+ const updatePosition = (0, react.useCallback)(() => {
2119
+ if (!anchorRef.current) return;
2120
+ const rect = anchorRef.current.getBoundingClientRect();
2121
+ setPopoverPos({
2122
+ bottom: window.innerHeight - rect.top + 6,
2123
+ left: Math.max(8, Math.min(rect.left, window.innerWidth - 330))
2124
+ });
2125
+ }, []);
2126
+ const handleToggle = (0, react.useCallback)((e) => {
2127
+ e.stopPropagation();
2128
+ if (!open) {
2129
+ updatePosition();
2130
+ refresh();
2131
+ }
2132
+ setOpen((prev) => !prev);
2133
+ setCreatingBranch(false);
2134
+ setFilter("");
2135
+ }, [
2136
+ open,
2137
+ refresh,
2138
+ updatePosition
2139
+ ]);
2140
+ (0, react.useEffect)(() => {
2141
+ if (!open) return;
2142
+ const onPointerDown = (e) => {
2143
+ const target = e.target;
2144
+ if (popoverRef.current?.contains(target) || anchorRef.current?.contains(target)) return;
2145
+ setOpen(false);
2146
+ };
2147
+ const onKeyDown = (e) => {
2148
+ if (e.key === "Escape") setOpen(false);
2149
+ };
2150
+ document.addEventListener("pointerdown", onPointerDown);
2151
+ document.addEventListener("keydown", onKeyDown);
2152
+ return () => {
2153
+ document.removeEventListener("pointerdown", onPointerDown);
2154
+ document.removeEventListener("keydown", onKeyDown);
2155
+ };
2156
+ }, [open]);
2157
+ const handleCheckout = (0, react.useCallback)(async (branchName, create = false) => {
2158
+ if (!checkout || switching) return;
2159
+ setSwitching(true);
2160
+ try {
2161
+ const res = await checkout(sessionId, branchName, create);
2162
+ if (res.success) {
2163
+ setOpen(false);
2164
+ setCreatingBranch(false);
2165
+ setNewBranchName("");
2166
+ await refresh();
2167
+ } else alert(res.message ?? "Checkout failed");
2168
+ } finally {
2169
+ setSwitching(false);
2170
+ }
2171
+ }, [
2172
+ checkout,
2173
+ refresh,
2174
+ sessionId,
2175
+ switching
2176
+ ]);
2177
+ const handleCreateBranchKeyDown = (0, react.useCallback)((e) => {
2178
+ if (e.key === "Enter") {
2179
+ const trimmed = newBranchName.trim();
2180
+ if (trimmed) handleCheckout(trimmed, true);
2181
+ } else if (e.key === "Escape") setCreatingBranch(false);
2182
+ }, [handleCheckout, newBranchName]);
2183
+ const handlePull = (0, react.useCallback)(async () => {
2184
+ if (!pull) return;
2185
+ await pull(sessionId);
2186
+ await refresh();
2187
+ }, [
2188
+ pull,
2189
+ refresh,
2190
+ sessionId
2191
+ ]);
2192
+ const handlePush = (0, react.useCallback)(async () => {
2193
+ if (!push) return;
2194
+ await push(sessionId);
2195
+ await refresh();
2196
+ }, [
2197
+ push,
2198
+ refresh,
2199
+ sessionId
2200
+ ]);
2201
+ const filteredLocal = (0, react.useMemo)(() => {
2202
+ if (!branches?.local) return [];
2203
+ const q = filter.trim().toLowerCase();
2204
+ return q ? branches.local.filter((b) => b.name.toLowerCase().includes(q)) : branches.local;
2205
+ }, [branches?.local, filter]);
2206
+ const filteredRemote = (0, react.useMemo)(() => {
2207
+ if (!branches?.remote) return [];
2208
+ const q = filter.trim().toLowerCase();
2209
+ return q ? branches.remote.filter((b) => b.name.toLowerCase().includes(q)) : branches.remote;
2210
+ }, [branches?.remote, filter]);
2211
+ if (status && !status.isRepo) return null;
2212
+ const currentBranchName = status?.branch || "master";
2213
+ return (0, react_jsx_runtime.jsxs)("span", {
2214
+ ref: anchorRef,
2215
+ className: GitBranchPill_module_css_default.anchor,
2216
+ "data-composer-stat": "git-branch",
2217
+ children: [(0, react_jsx_runtime.jsxs)("button", {
2218
+ type: "button",
2219
+ className: GitBranchPill_module_css_default.pill,
2220
+ "aria-haspopup": "dialog",
2221
+ "aria-expanded": open,
2222
+ title: `Git Branch: ${currentBranchName}`,
2223
+ onClick: handleToggle,
2224
+ children: [
2225
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutlineRegular, { className: GitBranchPill_module_css_default.icon }),
2226
+ (0, react_jsx_runtime.jsx)("span", {
2227
+ className: GitBranchPill_module_css_default.branchName,
2228
+ children: currentBranchName
2229
+ }),
2230
+ status !== null && status.ahead > 0 && (0, react_jsx_runtime.jsxs)("span", {
2231
+ className: `${GitBranchPill_module_css_default.badge} ${GitBranchPill_module_css_default.badgeAhead}`,
2232
+ children: ["↑", status.ahead]
2233
+ }),
2234
+ status !== null && status.behind > 0 && (0, react_jsx_runtime.jsxs)("span", {
2235
+ className: `${GitBranchPill_module_css_default.badge} ${GitBranchPill_module_css_default.badgeBehind}`,
2236
+ children: ["↓", status.behind]
2237
+ })
2238
+ ]
2239
+ }), open && popoverPos && (0, react_dom.createPortal)((0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.MenuSurface, {
2240
+ ref: popoverRef,
2241
+ className: GitBranchPill_module_css_default.popover,
2242
+ style: {
2243
+ bottom: `${popoverPos.bottom}px`,
2244
+ left: `${popoverPos.left}px`
2245
+ },
2246
+ children: [(0, react_jsx_runtime.jsxs)("div", {
2247
+ className: GitBranchPill_module_css_default.header,
2248
+ children: [
2249
+ (0, react_jsx_runtime.jsxs)("div", {
2250
+ className: GitBranchPill_module_css_default.searchRow,
2251
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutlineRegular, { className: GitBranchPill_module_css_default.searchIcon }), (0, react_jsx_runtime.jsx)("input", {
2252
+ autoFocus: true,
2253
+ className: GitBranchPill_module_css_default.searchInput,
2254
+ placeholder: "搜索或过滤分支...",
2255
+ value: filter,
2256
+ onChange: (e) => {
2257
+ setFilter(e.target.value);
2258
+ }
2259
+ })]
2260
+ }),
2261
+ (0, react_jsx_runtime.jsxs)("div", {
2262
+ className: GitBranchPill_module_css_default.actionBar,
2263
+ children: [(0, react_jsx_runtime.jsxs)("button", {
2264
+ type: "button",
2265
+ className: GitBranchPill_module_css_default.toolBtn,
2266
+ title: "新建分支",
2267
+ onClick: () => {
2268
+ setCreatingBranch((prev) => !prev);
2269
+ },
2270
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, { className: GitBranchPill_module_css_default.btnIcon }), (0, react_jsx_runtime.jsx)("span", { children: "新建分支" })]
2271
+ }), (0, react_jsx_runtime.jsxs)("div", {
2272
+ className: GitBranchPill_module_css_default.toolBtnGroup,
2273
+ children: [
2274
+ (0, react_jsx_runtime.jsx)("button", {
2275
+ type: "button",
2276
+ className: GitBranchPill_module_css_default.toolBtn,
2277
+ title: "拉取 (Pull)",
2278
+ onClick: () => {
2279
+ handlePull();
2280
+ },
2281
+ children: "Pull"
2282
+ }),
2283
+ (0, react_jsx_runtime.jsx)("button", {
2284
+ type: "button",
2285
+ className: GitBranchPill_module_css_default.toolBtn,
2286
+ title: "推送 (Push)",
2287
+ onClick: () => {
2288
+ handlePush();
2289
+ },
2290
+ children: "Push"
2291
+ }),
2292
+ (0, react_jsx_runtime.jsx)("button", {
2293
+ type: "button",
2294
+ className: GitBranchPill_module_css_default.toolBtn,
2295
+ title: "刷新状态",
2296
+ onClick: () => {
2297
+ refresh();
2298
+ },
2299
+ children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconRefreshOutlineRegular, { className: GitBranchPill_module_css_default.btnIcon })
2300
+ })
2301
+ ]
2302
+ })]
2303
+ }),
2304
+ creatingBranch && (0, react_jsx_runtime.jsx)("div", {
2305
+ className: GitBranchPill_module_css_default.newBranchBox,
2306
+ children: (0, react_jsx_runtime.jsx)("input", {
2307
+ autoFocus: true,
2308
+ className: GitBranchPill_module_css_default.newBranchInput,
2309
+ placeholder: "新分支名称 (按 Enter 创建)...",
2310
+ value: newBranchName,
2311
+ onChange: (e) => {
2312
+ setNewBranchName(e.target.value);
2313
+ },
2314
+ onKeyDown: handleCreateBranchKeyDown
2315
+ })
2316
+ })
2317
+ ]
2318
+ }), (0, react_jsx_runtime.jsxs)("div", {
2319
+ className: GitBranchPill_module_css_default.branchList,
2320
+ children: [
2321
+ (0, react_jsx_runtime.jsxs)("div", {
2322
+ className: GitBranchPill_module_css_default.groupLabel,
2323
+ children: [
2324
+ "本地分支 (",
2325
+ filteredLocal.length,
2326
+ ")"
2327
+ ]
2328
+ }),
2329
+ filteredLocal.map((b) => (0, react_jsx_runtime.jsxs)("button", {
2330
+ type: "button",
2331
+ className: `${GitBranchPill_module_css_default.branchItem} ${b.isCurrent ? GitBranchPill_module_css_default.currentBranch : ""}`,
2332
+ disabled: switching,
2333
+ onClick: () => {
2334
+ if (!b.isCurrent) handleCheckout(b.name);
2335
+ },
2336
+ children: [(0, react_jsx_runtime.jsxs)("div", {
2337
+ className: GitBranchPill_module_css_default.branchItemLeft,
2338
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutlineRegular, { className: GitBranchPill_module_css_default.itemIcon }), (0, react_jsx_runtime.jsx)("span", {
2339
+ className: GitBranchPill_module_css_default.itemText,
2340
+ children: b.name
2341
+ })]
2342
+ }), b.isCurrent ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutlineRegular, { className: GitBranchPill_module_css_default.checkMark }) : b.ahead !== void 0 && b.ahead > 0 && (0, react_jsx_runtime.jsxs)("span", {
2343
+ className: GitBranchPill_module_css_default.badge,
2344
+ children: ["↑", b.ahead]
2345
+ })]
2346
+ }, b.name)),
2347
+ filteredRemote.length > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
2348
+ className: GitBranchPill_module_css_default.groupLabel,
2349
+ style: { marginTop: "6px" },
2350
+ children: [
2351
+ "远程分支 (",
2352
+ filteredRemote.length,
2353
+ ")"
2354
+ ]
2355
+ }), filteredRemote.map((b) => (0, react_jsx_runtime.jsx)("button", {
2356
+ type: "button",
2357
+ className: GitBranchPill_module_css_default.branchItem,
2358
+ disabled: switching,
2359
+ onClick: () => {
2360
+ handleCheckout(b.name);
2361
+ },
2362
+ children: (0, react_jsx_runtime.jsxs)("div", {
2363
+ className: GitBranchPill_module_css_default.branchItemLeft,
2364
+ children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutlineRegular, { className: GitBranchPill_module_css_default.itemIcon }), (0, react_jsx_runtime.jsx)("span", {
2365
+ className: GitBranchPill_module_css_default.itemText,
2366
+ children: b.name
2367
+ })]
2368
+ })
2369
+ }, b.name))] }),
2370
+ filteredLocal.length === 0 && filteredRemote.length === 0 && (0, react_jsx_runtime.jsx)("div", {
2371
+ className: GitBranchPill_module_css_default.emptyTip,
2372
+ children: "未找到匹配的分支"
2373
+ })
2374
+ ]
2375
+ })]
2376
+ }), document.body)]
2377
+ });
2378
+ });
2379
+ //#endregion
2380
+ //#region lib/types/client/GitTitle.js
2381
+ /**
2382
+ * Git chip title component with branch glyph and title text.
2383
+ * @param props - Slot props including tab info hook.
2384
+ * @returns React node for tab chip.
2385
+ */
2386
+ function GitTitle({ useTabInfo }) {
2387
+ const { tab } = useTabInfo();
2388
+ return (0, react_jsx_runtime.jsxs)("span", {
2389
+ className: GitBody_module_css_default.titleContainer,
2390
+ children: [(0, react_jsx_runtime.jsx)("svg", {
2391
+ className: GitBody_module_css_default.titleIcon,
2392
+ width: "14",
2393
+ height: "14",
2394
+ viewBox: "0 0 16 16",
2395
+ fill: "currentColor",
2396
+ children: (0, react_jsx_runtime.jsx)("path", { d: "M11.75 2.5a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5zm-2.25.75a2.25 2.25 0 1 1 3 2.122V6A2.5 2.5 0 0 1 10 8.5H6a1 1 0 0 0-1 1v1.128a2.251 2.251 0 1 1-1.5 0V5.372a2.25 2.25 0 1 1 1.5 0v1.836A2.492 2.492 0 0 1 6 7h4a1 1 0 0 0 1-1v-.628A2.25 2.25 0 0 1 9.5 3.25zM4.25 12a.75.75 0 1 0 0 1.5.75.75 0 0 0 0-1.5zM3.5 3.25a.75.75 0 1 0 1.5 0 .75.75 0 0 0-1.5 0z" })
2397
+ }), (0, react_jsx_runtime.jsx)("span", {
2398
+ className: GitBody_module_css_default.titleText,
2399
+ children: tab.title
2400
+ })]
2401
+ });
2402
+ }
2403
+ //#endregion
2404
+ //#region lib/types/client/locales.js
2405
+ /**
2406
+ * Localized copy for the Git right-sidebar viewer and commands.
2407
+ */
2408
+ const NS = "gitView";
2409
+ const zh = {
2410
+ "type.label": "Git",
2411
+ "guide.title": "Git 版本控制",
2412
+ "guide.description": "查看项目代码变更、分支、提交历史与差异对比",
2413
+ "shortcut.noSession": "没有激活的会话",
2414
+ "tabs.changes": "更改",
2415
+ "tabs.history": "提交历史",
2416
+ "tabs.tree": "提交图谱树",
2417
+ "tabs.branches": "分支管理",
2418
+ "tabs.tags": "标签管理",
2419
+ "actions.refresh": "刷新状态",
2420
+ "actions.viewDiff": "查看差异",
2421
+ "actions.closeDiff": "收起差异",
2422
+ "actions.stage": "暂存",
2423
+ "actions.unstage": "取消暂存",
2424
+ "actions.stageAll": "全部暂存",
2425
+ "actions.unstageAll": "全部取消暂存",
2426
+ "actions.discard": "放弃更改",
2427
+ "actions.commit": "提交",
2428
+ "actions.commitAndPush": "提交并推送",
2429
+ "actions.checkout": "检出分支",
2430
+ "actions.newBranch": "新建分支",
2431
+ "actions.fetch": "获取远程",
2432
+ "actions.pull": "拉取",
2433
+ "actions.push": "推送",
2434
+ "commit.placeholder": "输入提交信息 (Ctrl+Enter 提交)...",
2435
+ "commit.emptyWarning": "请输入提交说明",
2436
+ "commit.success": "提交成功",
2437
+ "branch.filter": "搜索过滤分支...",
2438
+ "branch.local": "本地分支",
2439
+ "branch.remote": "远程分支",
2440
+ "branch.current": "当前分支",
2441
+ "branch.newPrompt": "输入新分支名称...",
2442
+ "branch.createAndCheckout": "创建并检出",
2443
+ "tree.author": "作者",
2444
+ "tree.date": "时间",
2445
+ "tree.hash": "哈希",
2446
+ "tree.changedFiles": "变更文件",
2447
+ "tree.selectCommit": "点击任意提交查看详情与代码差异",
2448
+ "status.clean": "工作树干净,无任何未提交更改",
2449
+ "status.notRepo": "当前工作区不是 Git 仓库",
2450
+ "status.staged": "已暂存更改",
2451
+ "status.unstaged": "工作区修改",
2452
+ "status.untracked": "未跟踪文件",
2453
+ "status.ahead": "领先 {count} 个提交",
2454
+ "status.behind": "落后 {count} 个提交",
2455
+ "diff.additions": "+{count}",
2456
+ "diff.deletions": "-{count}",
2457
+ "diff.empty": "无内容变动",
2458
+ "tag.filter": "搜索过滤标签 (名称、Hash、提交说明)...",
2459
+ "tag.newPrompt": "新建标签 (Tag)",
2460
+ "tag.nameLabel": "标签名称",
2461
+ "tag.namePlaceholder": "输入标签名称 (例如 v1.0.0)...",
2462
+ "tag.targetCommitLabel": "目标 Commit Hash (可选,留空为 HEAD)",
2463
+ "tag.messageLabel": "说明信息 (可选附注内容)",
2464
+ "tag.messagePrompt": "输入附注说明信息 (可选)...",
2465
+ "tag.createBtn": "创建标签",
2466
+ "tag.cancelBtn": "取消",
2467
+ "tag.locateBtn": "在图谱中定位",
2468
+ "tag.copyName": "复制标签名",
2469
+ "tag.deleteBtn": "删除",
2470
+ "tag.deleteConfirm": "确定要删除标签 \"{name}\" 吗?",
2471
+ "tag.empty": "暂无任何 Git 标签",
2472
+ "tag.annotated": "附注",
2473
+ "tag.locatedNotice": "已定位到标签 \"{name}\" 所在的提交",
2474
+ "actions.locate": "定位",
2475
+ "tree.colGraph": "图谱",
2476
+ "tree.colSubject": "提交说明与分支标记",
2477
+ "tree.colAuthor": "作者",
2478
+ "tree.colTime": "时间",
2479
+ "tree.colSha": "Commit SHA",
2480
+ "tree.searchPlaceholder": "搜索提交说明、SHA 或作者...",
2481
+ "tree.filterAll": "全部",
2482
+ "tree.filterMainline": "仅主线",
2483
+ "detail.title": "提交详情 (COMMIT DETAILS)",
2484
+ "detail.references": "包含引用 (REFERENCES)",
2485
+ "detail.author": "作者 (Author)",
2486
+ "detail.date": "提交时间 (Date)",
2487
+ "detail.parent": "父级提交 (Parent)",
2488
+ "detail.checkout": "检出分支 (Checkout)",
2489
+ "detail.createBranchOrTag": "创建分支 / 标签",
2490
+ "footer.showingCount": "已显示 {count} 条提交 (共 {total} 条)",
2491
+ "footer.loadMore": "加载更多",
2492
+ "footer.syncNormal": "分支同步正常",
2493
+ "footer.ahead": "本地领先 {count} 个提交",
2494
+ "footer.behind": "落后远程 {count} 个提交"
2495
+ };
2496
+ const en = {
2497
+ "type.label": "Git",
2498
+ "guide.title": "Git Source Control",
2499
+ "guide.description": "View project code changes, branches, commit log, and unified diffs",
2500
+ "shortcut.noSession": "No active session",
2501
+ "tabs.changes": "Changes",
2502
+ "tabs.history": "History",
2503
+ "tabs.tree": "Git Tree & Log",
2504
+ "tabs.branches": "Branches",
2505
+ "tabs.tags": "Tags",
2506
+ "actions.refresh": "Refresh status",
2507
+ "actions.viewDiff": "View Diff",
2508
+ "actions.closeDiff": "Collapse Diff",
2509
+ "actions.stage": "Stage",
2510
+ "actions.unstage": "Unstage",
2511
+ "actions.stageAll": "Stage All",
2512
+ "actions.unstageAll": "Unstage All",
2513
+ "actions.discard": "Discard",
2514
+ "actions.commit": "Commit",
2515
+ "actions.commitAndPush": "Commit and Push",
2516
+ "actions.checkout": "Checkout",
2517
+ "actions.newBranch": "New Branch",
2518
+ "actions.fetch": "Fetch",
2519
+ "actions.pull": "Pull",
2520
+ "actions.push": "Push",
2521
+ "commit.placeholder": "Commit message (Ctrl+Enter to commit)...",
2522
+ "commit.emptyWarning": "Please enter a commit message",
2523
+ "commit.success": "Committed successfully",
2524
+ "branch.filter": "Filter branches...",
2525
+ "branch.local": "Local Branches",
2526
+ "branch.remote": "Remote Branches",
2527
+ "branch.current": "Current Branch",
2528
+ "branch.newPrompt": "Enter new branch name...",
2529
+ "branch.createAndCheckout": "Create & Checkout",
2530
+ "tree.author": "Author",
2531
+ "tree.date": "Date",
2532
+ "tree.hash": "Hash",
2533
+ "tree.changedFiles": "Changed Files",
2534
+ "tree.selectCommit": "Select a commit to view details and code diff",
2535
+ "status.clean": "Working tree clean, no uncommitted changes",
2536
+ "status.notRepo": "Current workspace is not a Git repository",
2537
+ "status.staged": "Staged Changes",
2538
+ "status.unstaged": "Unstaged Changes",
2539
+ "status.untracked": "Untracked Files",
2540
+ "status.ahead": "{count} ahead",
2541
+ "status.behind": "{count} behind",
2542
+ "diff.additions": "+{count}",
2543
+ "diff.deletions": "-{count}",
2544
+ "diff.empty": "No content changes",
2545
+ "tag.filter": "Filter tags (name, hash, message)...",
2546
+ "tag.newPrompt": "New Tag",
2547
+ "tag.nameLabel": "Tag Name",
2548
+ "tag.namePlaceholder": "Enter tag name (e.g. v1.0.0)...",
2549
+ "tag.targetCommitLabel": "Target Commit Hash (optional, defaults to HEAD)",
2550
+ "tag.messageLabel": "Message (optional annotation)",
2551
+ "tag.messagePrompt": "Enter annotation message (optional)...",
2552
+ "tag.createBtn": "Create Tag",
2553
+ "tag.cancelBtn": "Cancel",
2554
+ "tag.locateBtn": "Locate in Graph",
2555
+ "tag.copyName": "Copy Tag Name",
2556
+ "tag.deleteBtn": "Delete",
2557
+ "tag.deleteConfirm": "Are you sure you want to delete tag \"{name}\"?",
2558
+ "tag.empty": "No Git tags found",
2559
+ "tag.annotated": "Annotated",
2560
+ "tag.locatedNotice": "Located commit for tag \"{name}\"",
2561
+ "actions.locate": "Locate",
2562
+ "tree.colGraph": "Graph",
2563
+ "tree.colSubject": "Commit Subject & References",
2564
+ "tree.colAuthor": "Author",
2565
+ "tree.colTime": "Time",
2566
+ "tree.colSha": "Commit SHA",
2567
+ "tree.searchPlaceholder": "Search subject, SHA or author...",
2568
+ "tree.filterAll": "All",
2569
+ "tree.filterMainline": "Mainline",
2570
+ "detail.title": "COMMIT DETAILS",
2571
+ "detail.references": "REFERENCES",
2572
+ "detail.author": "Author",
2573
+ "detail.date": "Date",
2574
+ "detail.parent": "Parent",
2575
+ "detail.checkout": "Checkout",
2576
+ "detail.createBranchOrTag": "Create Branch / Tag",
2577
+ "footer.showingCount": "Showing {count} commits (total {total})",
2578
+ "footer.loadMore": "Load more",
2579
+ "footer.syncNormal": "Branch in sync",
2580
+ "footer.ahead": "{count} ahead of remote",
2581
+ "footer.behind": "{count} behind remote"
2582
+ };
2583
+ //#endregion
2584
+ //#region lib/types/client/index.js
2585
+ /**
2586
+ * Browser entry for the experimental Git right-sidebar plugin.
2587
+ */
2588
+ /**
2589
+ * Required browser services.
2590
+ */
2591
+ const inject = [
2592
+ "connection",
2593
+ "slots",
2594
+ "locale",
2595
+ "sidebarRightTabs",
2596
+ "sidebarRight"
2597
+ ];
2598
+ /**
2599
+ * Client plugin body: registers Git tab definition, locales, shortcut, and components.
2600
+ * @param ctx - Client context carrying slots and connection services.
2601
+ */
2602
+ function apply(ctx) {
2603
+ const t = ctx.locale.bind(NS);
2604
+ ctx.effect(() => ctx.locale.register(NS, {
2605
+ zh,
2606
+ en
2607
+ }), "experimental-git: locales");
2608
+ ctx.effect(() => ctx.sidebarRightTabs.register(gitDefinition(t)), "experimental-git: tab definition");
2609
+ ctx.inject(["shortcuts"], (scope) => {
2610
+ scope.effect(() => scope.shortcuts.register({
2611
+ id: "workspace.git",
2612
+ label: () => t("guide.title"),
2613
+ aliases: [
2614
+ "workspace git",
2615
+ "git",
2616
+ "source control"
2617
+ ],
2618
+ defaults: {
2619
+ "desktop:macos": {
2620
+ code: "KeyG",
2621
+ modifiers: ["primary", "shift"]
2622
+ },
2623
+ "desktop:windows": {
2624
+ code: "KeyG",
2625
+ modifiers: ["primary", "shift"]
2626
+ },
2627
+ "desktop:linux": {
2628
+ code: "KeyG",
2629
+ modifiers: ["primary", "shift"]
2630
+ },
2631
+ "web:macos": {
2632
+ code: "KeyG",
2633
+ modifiers: ["primary", "shift"]
2634
+ },
2635
+ "web:windows": {
2636
+ code: "KeyG",
2637
+ modifiers: ["primary", "shift"]
2638
+ }
2639
+ },
2640
+ regions: [
2641
+ "page",
2642
+ "editable",
2643
+ "terminal"
2644
+ ],
2645
+ modals: [],
2646
+ resolve: ({ target: element }) => {
2647
+ const target = scope.sidebarRight.commandTarget(element);
2648
+ if (target === void 0) return {
2649
+ status: "blocked",
2650
+ reason: t("shortcut.noSession")
2651
+ };
2652
+ return {
2653
+ status: "handled",
2654
+ run: () => {
2655
+ scope.sidebarRight.openTabFromTarget("git", target);
2656
+ }
2657
+ };
2658
+ }
2659
+ }), "experimental-git: shortcut");
2660
+ });
2661
+ const getConnection = () => {
2662
+ const handle = ctx.get("connection");
2663
+ if (!handle) throw new Error("Connection service not available");
2664
+ return handle;
2665
+ };
2666
+ const actions = {
2667
+ getStatus: async (sessionId) => {
2668
+ const res = await getConnection().rpc.call("/git", "status", { sessionId });
2669
+ if (!res.ok) throw new Error(res.error.message);
2670
+ return res.value;
2671
+ },
2672
+ getLog: async (sessionId, maxCount) => {
2673
+ const res = await getConnection().rpc.call("/git", "log", {
2674
+ sessionId,
2675
+ maxCount
2676
+ });
2677
+ if (!res.ok) throw new Error(res.error.message);
2678
+ return res.value;
2679
+ },
2680
+ getCommitDetails: async (sessionId, commit) => {
2681
+ const res = await getConnection().rpc.call("/git", "commitDetails", {
2682
+ sessionId,
2683
+ commit
2684
+ });
2685
+ if (!res.ok) throw new Error(res.error.message);
2686
+ return res.value;
2687
+ },
2688
+ getDiff: async (sessionId, options) => {
2689
+ const res = await getConnection().rpc.call("/git", "diff", {
2690
+ sessionId,
2691
+ ...options
2692
+ });
2693
+ if (!res.ok) throw new Error(res.error.message);
2694
+ return res.value;
2695
+ },
2696
+ getBranches: async (sessionId) => {
2697
+ const res = await getConnection().rpc.call("/git", "branches", { sessionId });
2698
+ if (!res.ok) throw new Error(res.error.message);
2699
+ return res.value;
2700
+ },
2701
+ checkout: async (sessionId, branch, create) => {
2702
+ const res = await getConnection().rpc.call("/git", "checkout", {
2703
+ sessionId,
2704
+ branch,
2705
+ create
2706
+ });
2707
+ if (!res.ok) return {
2708
+ success: false,
2709
+ message: res.error.message
2710
+ };
2711
+ return res.value;
2712
+ },
2713
+ stage: async (sessionId, paths) => {
2714
+ const res = await getConnection().rpc.call("/git", "stage", {
2715
+ sessionId,
2716
+ paths
2717
+ });
2718
+ if (!res.ok) return {
2719
+ success: false,
2720
+ message: res.error.message
2721
+ };
2722
+ return res.value;
2723
+ },
2724
+ unstage: async (sessionId, paths) => {
2725
+ const res = await getConnection().rpc.call("/git", "unstage", {
2726
+ sessionId,
2727
+ paths
2728
+ });
2729
+ if (!res.ok) return {
2730
+ success: false,
2731
+ message: res.error.message
2732
+ };
2733
+ return res.value;
2734
+ },
2735
+ discard: async (sessionId, paths) => {
2736
+ const res = await getConnection().rpc.call("/git", "discard", {
2737
+ sessionId,
2738
+ paths
2739
+ });
2740
+ if (!res.ok) return {
2741
+ success: false,
2742
+ message: res.error.message
2743
+ };
2744
+ return res.value;
2745
+ },
2746
+ commit: async (sessionId, message) => {
2747
+ const res = await getConnection().rpc.call("/git", "commit", {
2748
+ sessionId,
2749
+ message
2750
+ });
2751
+ if (!res.ok) return {
2752
+ success: false,
2753
+ message: res.error.message
2754
+ };
2755
+ return res.value;
2756
+ },
2757
+ fetch: async (sessionId) => {
2758
+ const res = await getConnection().rpc.call("/git", "fetch", { sessionId });
2759
+ if (!res.ok) return {
2760
+ success: false,
2761
+ message: res.error.message
2762
+ };
2763
+ return res.value;
2764
+ },
2765
+ pull: async (sessionId) => {
2766
+ const res = await getConnection().rpc.call("/git", "pull", { sessionId });
2767
+ if (!res.ok) return {
2768
+ success: false,
2769
+ message: res.error.message
2770
+ };
2771
+ return res.value;
2772
+ },
2773
+ push: async (sessionId) => {
2774
+ const res = await getConnection().rpc.call("/git", "push", { sessionId });
2775
+ if (!res.ok) return {
2776
+ success: false,
2777
+ message: res.error.message
2778
+ };
2779
+ return res.value;
2780
+ },
2781
+ getTags: async (sessionId) => {
2782
+ const res = await getConnection().rpc.call("/git", "tags", { sessionId });
2783
+ if (!res.ok) throw new Error(res.error.message);
2784
+ return res.value;
2785
+ },
2786
+ createTag: async (sessionId, name, commit, message) => {
2787
+ const res = await getConnection().rpc.call("/git", "createTag", {
2788
+ sessionId,
2789
+ name,
2790
+ commit,
2791
+ message
2792
+ });
2793
+ if (!res.ok) return {
2794
+ success: false,
2795
+ message: res.error.message
2796
+ };
2797
+ return res.value;
2798
+ },
2799
+ deleteTag: async (sessionId, name) => {
2800
+ const res = await getConnection().rpc.call("/git", "deleteTag", {
2801
+ sessionId,
2802
+ name
2803
+ });
2804
+ if (!res.ok) return {
2805
+ success: false,
2806
+ message: res.error.message
2807
+ };
2808
+ return res.value;
2809
+ }
2810
+ };
2811
+ ctx.effect(() => ctx.slots.inject("sidebar.right.pane.tab", () => ctx.slots.register({
2812
+ name: "sidebar.right.pane.tab",
2813
+ key: GIT_ID,
2814
+ locale: NS,
2815
+ inject: () => actions
2816
+ }, GitBody)), "experimental-git: tab body");
2817
+ ctx.effect(() => ctx.slots.inject("sidebar.right.pane.tab.title", () => ctx.slots.register({
2818
+ name: "sidebar.right.pane.tab.title",
2819
+ key: GIT_ID
2820
+ }, GitTitle)), "experimental-git: tab title");
2821
+ ctx.slots.inject("conversation.composer.dock", () => ctx.slots.register({
2822
+ name: "conversation.composer.dock",
2823
+ id: "git-branch",
2824
+ order: -1,
2825
+ locale: NS,
2826
+ inject: () => actions
2827
+ }, GitBranchPill));
2828
+ }
2829
+ //#endregion
2830
+ exports.apply = apply;
2831
+ exports.inject = inject;
2832
+ return module.exports;
2833
+ }
2834
+ });
2835
+
2836
+ //# sourceMappingURL=client.js.map