@civilization/dsh-git-workbench 0.0.0-stage → 0.4.1

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