dsh-vscode-workbench 0.1.1 → 0.1.3

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/README.en.md CHANGED
@@ -34,13 +34,6 @@ The workbench mounts through the official `sidebar.footer.action` and `shell.ove
34
34
 
35
35
  ## Installation
36
36
 
37
- Install the aggregate package for the complete workbench with terminal integration:
38
-
39
- ```bash
40
- dsh plugin --profile web add dsh-vscode-plugin
41
- ```
42
-
43
- Install only the workbench and its extension API:
44
37
 
45
38
  ```bash
46
39
  dsh plugin --profile web add dsh-vscode-workbench
@@ -55,12 +48,11 @@ dsh plugin --profile web add dsh-vscode-workbench
55
48
  | `Ctrl+Shift+G` | Open Source Control |
56
49
  | `Ctrl+S` | Save the active file |
57
50
  | `Ctrl+Alt+B` | Toggle the DSH conversation panel |
51
+ | `Ctrl+\`` | Toggle the registered terminal panel |
52
+ | `Ctrl+Shift+\`` | Create a terminal and show its panel |
58
53
 
59
- Terminal shortcuts are registered by `dsh-vscode-plugin`.
60
-
61
- ## Extension API
54
+ The terminal remains an independent plugin. This workbench only owns the shortcuts and invokes it through `registerBottomPanel()` and the `terminal.new` command.
62
55
 
63
- The browser exposes a `vscodeWorkbench` service for registering bottom panels and commands and controlling workbench visibility. `dsh-vscode-plugin` uses this API to mount `@xterm/xterm`.
64
56
 
65
57
  ## Security
66
58
 
package/README.md CHANGED
@@ -33,14 +33,6 @@
33
33
 
34
34
  ## 安装
35
35
 
36
- 推荐安装包含终端适配器的聚合包:
37
-
38
- ```bash
39
- dsh plugin --profile web add dsh-vscode-plugin
40
- ```
41
-
42
- 仅使用工作台和扩展 API:
43
-
44
36
  ```bash
45
37
  dsh plugin --profile web add dsh-vscode-workbench
46
38
  ```
@@ -54,12 +46,11 @@ dsh plugin --profile web add dsh-vscode-workbench
54
46
  | `Ctrl+Shift+G` | 打开源代码管理 |
55
47
  | `Ctrl+S` | 保存当前文件 |
56
48
  | `Ctrl+Alt+B` | 显示或隐藏 DSH 对话栏 |
49
+ | `Ctrl+\`` | 显示或隐藏已注册的终端面板 |
50
+ | `Ctrl+Shift+\`` | 新建终端并显示终端面板 |
57
51
 
58
- 终端快捷键由 `dsh-vscode-plugin` 注册。
59
-
60
- ## 扩展
52
+ 终端仍由独立插件提供;本工作台只注册快捷键,并通过 `registerBottomPanel()` 和 `terminal.new` 命令调用它。
61
53
 
62
- 浏览器端提供 `vscodeWorkbench` 服务,可注册底部面板和命令,并控制工作台与面板显隐。`dsh-vscode-plugin` 使用该接口挂载 `@xterm/xterm`。
63
54
 
64
55
  ## 安全
65
56
 
package/lib/client.js CHANGED
@@ -4191,6 +4191,17 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4191
4191
  //#endregion
4192
4192
  //#region src/client/MonacoEditor.tsx
4193
4193
  let loading;
4194
+ /** Monaco chrome used by both editors so only the narrow native scrollbar remains. */
4195
+ const WORKBENCH_EDITOR_CHROME = {
4196
+ minimap: { enabled: false },
4197
+ renderOverviewRuler: false,
4198
+ overviewRulerLanes: 0,
4199
+ hideCursorInOverviewRuler: true,
4200
+ scrollbar: {
4201
+ verticalScrollbarSize: 10,
4202
+ horizontalScrollbarSize: 10
4203
+ }
4204
+ };
4194
4205
  function loadMonaco() {
4195
4206
  loading ??= new Promise((resolve, reject) => {
4196
4207
  const start = () => {
@@ -4233,9 +4244,8 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4233
4244
  renderSideBySide: props.mode === "split",
4234
4245
  theme: props.theme === "dark" ? "vs-dark" : "vs",
4235
4246
  fontSize: 14,
4236
- minimap: { enabled: false },
4247
+ ...WORKBENCH_EDITOR_CHROME,
4237
4248
  originalEditable: false,
4238
- renderOverviewRuler: true,
4239
4249
  ignoreTrimWhitespace: false
4240
4250
  });
4241
4251
  instance.setModel({
@@ -4300,7 +4310,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4300
4310
  automaticLayout: true,
4301
4311
  theme: props.theme === "dark" ? "vs-dark" : "vs",
4302
4312
  fontSize: 14,
4303
- minimap: { enabled: true },
4313
+ ...WORKBENCH_EDITOR_CHROME,
4304
4314
  wordWrap: "off"
4305
4315
  });
4306
4316
  editor.current = instance;
@@ -4427,6 +4437,37 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4427
4437
  });
4428
4438
  }
4429
4439
  //#endregion
4440
+ //#region src/client/workspaceState.ts
4441
+ /** Remove editor state that belongs to the previous workspace. */
4442
+ function resetWorkspaceDocuments() {
4443
+ return {
4444
+ tabs: [],
4445
+ active: void 0,
4446
+ error: void 0
4447
+ };
4448
+ }
4449
+ /** Identifies responses that still belong to the active workspace request. */
4450
+ var WorkspaceRequestScope = class {
4451
+ epoch = 0;
4452
+ /** Begin loading another workspace and invalidate earlier work. */
4453
+ begin() {
4454
+ this.epoch += 1;
4455
+ return this.epoch;
4456
+ }
4457
+ /** Return the active workspace request identifier. */
4458
+ current() {
4459
+ return this.epoch;
4460
+ }
4461
+ /** Invalidate an active request while preserving any newer request. */
4462
+ invalidate(epoch) {
4463
+ if (this.epoch === epoch) this.epoch += 1;
4464
+ }
4465
+ /** Return whether a response may update the current workspace. */
4466
+ isCurrent(epoch) {
4467
+ return epoch === this.epoch;
4468
+ }
4469
+ };
4470
+ //#endregion
4430
4471
  //#region src/client/Workbench.tsx
4431
4472
  /** Return the basename shown in a tab while preserving its full internal path. */
4432
4473
  function tabLabel(tab) {
@@ -4753,20 +4794,33 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4753
4794
  }
4754
4795
  function graphRows(commits) {
4755
4796
  const visible = new Set(commits.map((commit) => commit.hash));
4756
- let lanes = commits[0] ? [commits[0].hash] : [];
4797
+ let nextColor = 0;
4798
+ let lanes = commits[0] ? [{
4799
+ hash: commits[0].hash,
4800
+ color: nextColor++
4801
+ }] : [];
4757
4802
  return commits.map((commit) => {
4758
- let lane = lanes.indexOf(commit.hash);
4803
+ let lane = lanes.findIndex((track) => track.hash === commit.hash);
4759
4804
  if (lane < 0) {
4760
- lanes = [commit.hash, ...lanes];
4805
+ lanes = [{
4806
+ hash: commit.hash,
4807
+ color: nextColor++
4808
+ }, ...lanes];
4761
4809
  lane = 0;
4762
4810
  }
4763
4811
  const before = [...lanes];
4764
- const after = before.filter((hash) => hash !== commit.hash);
4812
+ const current = before[lane];
4813
+ const after = before.filter((track) => track.hash !== commit.hash);
4765
4814
  const parents = commit.parents.filter((parent) => visible.has(parent));
4766
4815
  parents.forEach((parent, index) => {
4767
- if (!after.includes(parent)) after.splice(Math.min(lane + index, after.length), 0, parent);
4816
+ if (after.some((track) => track.hash === parent)) return;
4817
+ const color = index === 0 ? current.color : nextColor++;
4818
+ after.splice(Math.min(lane + index, after.length), 0, {
4819
+ hash: parent,
4820
+ color
4821
+ });
4768
4822
  });
4769
- const parentLanes = parents.map((parent) => after.indexOf(parent)).filter((index) => index >= 0);
4823
+ const parentLanes = parents.map((parent) => after.findIndex((track) => track.hash === parent)).filter((index) => index >= 0);
4770
4824
  lanes = after;
4771
4825
  return {
4772
4826
  commit,
@@ -4784,15 +4838,23 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4784
4838
  "#d9a441",
4785
4839
  "#9b7bea"
4786
4840
  ];
4787
- function graphColor(lane) {
4788
- return GRAPH_COLORS[lane % GRAPH_COLORS.length];
4841
+ function graphColor(color) {
4842
+ return GRAPH_COLORS[color % GRAPH_COLORS.length];
4789
4843
  }
4790
4844
  function graphWidth(row) {
4791
4845
  return Math.max(row.before.length, row.after.length, row.lane + 1, 1) * 14 + 8;
4792
4846
  }
4847
+ /** Draw a fixed-radius, orthogonal transition between two graph lanes. */
4848
+ function graphTrackPath(from, to, startY, endY, bendY) {
4849
+ if (from === to) return `M ${from} ${startY} V ${endY}`;
4850
+ const direction = Math.sign(to - from);
4851
+ const radius = Math.min(5, Math.abs(to - from) / 2, Math.abs(bendY - startY), Math.abs(endY - bendY));
4852
+ return `M ${from} ${startY} V ${bendY - radius} Q ${from} ${bendY} ${from + direction * radius} ${bendY} H ${to - direction * radius} Q ${to} ${bendY} ${to} ${bendY + radius} V ${endY}`;
4853
+ }
4793
4854
  function GraphTracks({ row }) {
4794
4855
  const width = graphWidth(row);
4795
4856
  const x = row.lane * 14 + 8;
4857
+ const current = row.before[row.lane];
4796
4858
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
4797
4859
  className: "dvw-graph-svg",
4798
4860
  width,
@@ -4800,41 +4862,44 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4800
4862
  viewBox: `0 0 ${width} 38`,
4801
4863
  "aria-hidden": "true",
4802
4864
  children: [
4803
- row.before.map((hash, lane) => {
4804
- if (hash === row.commit.hash) return null;
4805
- const target = row.after.indexOf(hash);
4865
+ row.before.map((track, lane) => {
4866
+ if (track.hash === row.commit.hash) return null;
4867
+ const target = row.after.findIndex((next) => next.hash === track.hash);
4806
4868
  const nextLane = target >= 0 ? target : lane;
4807
- const next = nextLane * 14 + 8;
4808
- const start = lane * 14 + 8;
4809
4869
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
4810
- d: `M ${start} 0 C ${start} 14 ${next} 24 ${next} 38`,
4870
+ d: graphTrackPath(lane * 14 + 8, nextLane * 14 + 8, 0, 38, 19),
4811
4871
  fill: "none",
4812
- stroke: graphColor(nextLane),
4813
- strokeWidth: "2"
4814
- }, `continue-${hash}`);
4872
+ stroke: graphColor(track.color),
4873
+ strokeWidth: "2",
4874
+ vectorEffect: "non-scaling-stroke"
4875
+ }, `continue-${track.hash}`);
4815
4876
  }),
4816
4877
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
4817
4878
  d: `M ${x} 0 V 19`,
4818
4879
  fill: "none",
4819
- stroke: graphColor(row.lane),
4820
- strokeWidth: "2"
4880
+ stroke: graphColor(current.color),
4881
+ strokeWidth: "2",
4882
+ vectorEffect: "non-scaling-stroke"
4821
4883
  }),
4822
4884
  row.parentLanes.map((parent, index) => {
4823
4885
  const target = parent * 14 + 8;
4886
+ const track = row.after[parent];
4824
4887
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
4825
- d: `M ${x} 19 C ${x} 27 ${target} 30 ${target} 38`,
4888
+ d: graphTrackPath(x, target, 19, 38, 29),
4826
4889
  fill: "none",
4827
- stroke: graphColor(parent),
4828
- strokeWidth: "2"
4829
- }, `parent-${parent}-${index}`);
4890
+ stroke: graphColor(track.color),
4891
+ strokeWidth: "2",
4892
+ vectorEffect: "non-scaling-stroke"
4893
+ }, `parent-${track.hash}-${index}`);
4830
4894
  }),
4831
4895
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
4832
4896
  cx: x,
4833
4897
  cy: "19",
4834
4898
  r: "5",
4835
4899
  fill: "var(--dvw-surface-1)",
4836
- stroke: graphColor(row.lane),
4837
- strokeWidth: "2"
4900
+ stroke: graphColor(current.color),
4901
+ strokeWidth: "2",
4902
+ vectorEffect: "non-scaling-stroke"
4838
4903
  })
4839
4904
  ]
4840
4905
  });
@@ -4848,15 +4913,15 @@ Please report this to https://github.com/markedjs/marked.`, e) {
4848
4913
  viewBox: `0 0 ${width} 100`,
4849
4914
  preserveAspectRatio: "none",
4850
4915
  "aria-hidden": "true",
4851
- children: row.after.map((hash, lane) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
4916
+ children: row.after.map((track, lane) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
4852
4917
  x1: lane * 14 + 8,
4853
4918
  y1: "0",
4854
4919
  x2: lane * 14 + 8,
4855
4920
  y2: "100",
4856
- stroke: graphColor(lane),
4921
+ stroke: graphColor(track.color),
4857
4922
  strokeWidth: "2",
4858
4923
  vectorEffect: "non-scaling-stroke"
4859
- }, hash))
4924
+ }, track.hash))
4860
4925
  });
4861
4926
  }
4862
4927
  function CommitGraph({ commits, expanded, files, onToggle, onOpenFile }) {
@@ -5234,6 +5299,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
5234
5299
  const [chatWidth, setChatWidth] = (0, react.useState)(() => Math.max(400, Math.min(720, Math.round(Number(localStorage.getItem("dvw:dsh-chat-width")) || 420))));
5235
5300
  const [chatVisible, setChatVisible] = (0, react.useState)(() => localStorage.getItem("dvw:dsh-chat-visible") !== "closed");
5236
5301
  const [outlineVisible, setOutlineVisible] = (0, react.useState)(() => localStorage.getItem("dvw:outline") !== "closed");
5302
+ const tabsRef = (0, react.useRef)(tabs);
5303
+ tabsRef.current = tabs;
5304
+ const workspaceRequests = (0, react.useRef)(new WorkspaceRequestScope());
5237
5305
  const dshDark = useDshDarkTheme();
5238
5306
  const [theme, setTheme] = (0, react.useState)(() => {
5239
5307
  const saved = localStorage.getItem("dvw:theme");
@@ -5256,9 +5324,69 @@ Please report this to https://github.com/markedjs/marked.`, e) {
5256
5324
  window.addEventListener("keydown", onKey, true);
5257
5325
  return () => window.removeEventListener("keydown", onKey, true);
5258
5326
  }, [snapshot.visible]);
5327
+ const openForWorkspace = async (targetSessionId, epoch, path, line, column) => {
5328
+ if (!workspaceRequests.current.isCurrent(epoch)) return;
5329
+ if (tabsRef.current.find((tab) => tab.path === path)) {
5330
+ setActive(path);
5331
+ setTabs((rows) => rows.map((tab) => tab.path === path ? {
5332
+ ...tab,
5333
+ line,
5334
+ column
5335
+ } : tab));
5336
+ return;
5337
+ }
5338
+ if (/\.(?:avif|bmp|gif|ico|jpe?g|png|svg|webp)$/i.test(path)) {
5339
+ const imageUrl = `/dsh-vscode/file?sessionId=${encodeURIComponent(targetSessionId)}&path=${encodeURIComponent(path)}`;
5340
+ if (!workspaceRequests.current.isCurrent(epoch)) return;
5341
+ setTabs((rows) => workspaceRequests.current.isCurrent(epoch) ? [...rows.filter((tab) => tab.path !== path), {
5342
+ path,
5343
+ content: "",
5344
+ draft: "",
5345
+ revision: "",
5346
+ size: 0,
5347
+ binary: false,
5348
+ tooLarge: false,
5349
+ dirty: false,
5350
+ imageUrl
5351
+ }] : rows);
5352
+ setActive(path);
5353
+ return;
5354
+ }
5355
+ try {
5356
+ const doc = await api("fs.read", {
5357
+ sessionId: targetSessionId,
5358
+ path
5359
+ });
5360
+ if (!workspaceRequests.current.isCurrent(epoch)) return;
5361
+ if (doc.binary || doc.tooLarge) {
5362
+ setError(doc.binary ? "二进制文件不能在文本编辑器中打开" : `文件超过 5 MiB:${path}`);
5363
+ return;
5364
+ }
5365
+ setTabs((rows) => workspaceRequests.current.isCurrent(epoch) ? [...rows.filter((tab) => tab.path !== path), {
5366
+ ...doc,
5367
+ draft: doc.content,
5368
+ dirty: false,
5369
+ line,
5370
+ column,
5371
+ preview: /\.md$/i.test(path)
5372
+ }] : rows);
5373
+ setActive(path);
5374
+ } catch (error) {
5375
+ if (workspaceRequests.current.isCurrent(epoch)) setError(String(error));
5376
+ }
5377
+ };
5259
5378
  (0, react.useEffect)(() => {
5260
5379
  if (!snapshot.visible || sessionId === void 0) return;
5261
- api("workspace", { sessionId }).then((value) => {
5380
+ const epoch = workspaceRequests.current.begin();
5381
+ const cleared = resetWorkspaceDocuments();
5382
+ setWorkspace(void 0);
5383
+ setTabs(cleared.tabs);
5384
+ tabsRef.current = cleared.tabs;
5385
+ setActive(cleared.active);
5386
+ setError(cleared.error);
5387
+ const controller = new AbortController();
5388
+ api("workspace", { sessionId }, controller.signal).then((value) => {
5389
+ if (!workspaceRequests.current.isCurrent(epoch)) return;
5262
5390
  setWorkspace(value);
5263
5391
  const saved = localStorage.getItem(`dvw:${value.cwd}`);
5264
5392
  if (saved) try {
@@ -5266,9 +5394,15 @@ Please report this to https://github.com/markedjs/marked.`, e) {
5266
5394
  if (parsed.view) service.show(parsed.view);
5267
5395
  if (typeof parsed.panelHeight === "number") setPanelHeight(parsed.panelHeight);
5268
5396
  if (typeof parsed.sideWidth === "number") setSideWidth(Math.max(210, Math.min(640, Math.round(parsed.sideWidth))));
5269
- for (const path of parsed.paths ?? []) open(path);
5397
+ for (const path of parsed.paths ?? []) openForWorkspace(sessionId, epoch, path);
5270
5398
  } catch {}
5271
- }).catch((error) => setError(String(error)));
5399
+ }).catch((error) => {
5400
+ if (!controller.signal.aborted && workspaceRequests.current.isCurrent(epoch)) setError(String(error));
5401
+ });
5402
+ return () => {
5403
+ controller.abort();
5404
+ workspaceRequests.current.invalidate(epoch);
5405
+ };
5272
5406
  }, [snapshot.visible, sessionId]);
5273
5407
  (0, react.useEffect)(() => {
5274
5408
  if (workspace) localStorage.setItem(`dvw:${workspace.cwd}`, JSON.stringify({
@@ -5299,52 +5433,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
5299
5433
  }, [snapshot.visible, sessionId]);
5300
5434
  const open = async (path, line, column) => {
5301
5435
  if (sessionId === void 0) return;
5302
- if (tabs.find((t) => t.path === path)) {
5303
- setActive(path);
5304
- setTabs((rows) => rows.map((t) => t.path === path ? {
5305
- ...t,
5306
- line,
5307
- column
5308
- } : t));
5309
- return;
5310
- }
5311
- if (/\.(?:avif|bmp|gif|ico|jpe?g|png|svg|webp)$/i.test(path)) {
5312
- const imageUrl = `/dsh-vscode/file?sessionId=${encodeURIComponent(sessionId)}&path=${encodeURIComponent(path)}`;
5313
- setTabs((rows) => [...rows, {
5314
- path,
5315
- content: "",
5316
- draft: "",
5317
- revision: "",
5318
- size: 0,
5319
- binary: false,
5320
- tooLarge: false,
5321
- dirty: false,
5322
- imageUrl
5323
- }]);
5324
- setActive(path);
5325
- return;
5326
- }
5327
- try {
5328
- const doc = await api("fs.read", {
5329
- sessionId,
5330
- path
5331
- });
5332
- if (doc.binary || doc.tooLarge) {
5333
- setError(doc.binary ? "二进制文件不能在文本编辑器中打开" : `文件超过 5 MiB:${path}`);
5334
- return;
5335
- }
5336
- setTabs((rows) => [...rows, {
5337
- ...doc,
5338
- draft: doc.content,
5339
- dirty: false,
5340
- line,
5341
- column,
5342
- preview: /\.md$/i.test(path)
5343
- }]);
5344
- setActive(path);
5345
- } catch (error) {
5346
- setError(String(error));
5347
- }
5436
+ await openForWorkspace(sessionId, workspaceRequests.current.current(), path, line, column);
5348
5437
  };
5349
5438
  (0, react.useEffect)(() => {
5350
5439
  const listener = (event) => void open(event.detail);
@@ -5963,11 +6052,29 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
5963
6052
  };
5964
6053
  }
5965
6054
  //#endregion
6055
+ //#region src/client/shortcuts.ts
6056
+ /** Handle terminal shortcuts through contributions registered by a terminal adapter. */
6057
+ function handleTerminalShortcut(event, workbench) {
6058
+ if (event.isComposing || !event.ctrlKey || event.altKey || event.code !== "Backquote") return false;
6059
+ if (!workbench.getPanels().some((panel) => panel.id === "terminal")) return false;
6060
+ event.preventDefault();
6061
+ event.stopImmediatePropagation();
6062
+ workbench.show();
6063
+ if (event.shiftKey) {
6064
+ if (workbench.getSnapshot().bottomPanel !== "terminal") workbench.toggleBottomPanel("terminal");
6065
+ queueMicrotask(() => workbench.runCommand("terminal.new"));
6066
+ } else workbench.toggleBottomPanel("terminal");
6067
+ return true;
6068
+ }
6069
+ //#endregion
5966
6070
  //#region src/client/index.tsx
5967
- const Overlay = ({ service, useSessions }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Workbench, {
5968
- service,
5969
- useSessions
5970
- });
6071
+ const Overlay = ({ service, useSessions }) => {
6072
+ const sessionId = useSessions((state) => state.current);
6073
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Workbench, {
6074
+ service,
6075
+ useSessions
6076
+ }, sessionId ?? "no-session");
6077
+ };
5971
6078
  const Footer = ({ service, wide }) => {
5972
6079
  const marker = (0, react.useRef)(null);
5973
6080
  const [target, setTarget] = (0, react.useState)();
@@ -6018,6 +6125,7 @@ body[data-ds-dark-theme] .dvw-overlay,.dvw-overlay[data-dvw-theme=dark]{color-sc
6018
6125
  }, Overlay));
6019
6126
  ctx.effect(() => {
6020
6127
  const onKey = (event) => {
6128
+ if (handleTerminalShortcut(event, service)) return;
6021
6129
  if (event.isComposing || !event.ctrlKey || event.altKey) return;
6022
6130
  const view = event.shiftKey && event.code === "KeyE" ? "explorer" : event.shiftKey && event.code === "KeyF" ? "search" : event.shiftKey && event.code === "KeyG" ? "git" : void 0;
6023
6131
  if (view !== void 0) {