@youtyan/code-viewer 0.12.0 → 0.13.0

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/web/app.js CHANGED
@@ -1119,6 +1119,7 @@ Details: ${JSON.stringify(output)}` : "";
1119
1119
  var PENCIL_16_PATH = "M11.013 1.427a1.75 1.75 0 0 1 2.474 0l1.086 1.086a1.75 1.75 0 0 1 0 2.474l-8.61 8.61c-.21.21-.47.364-.756.445l-3.251.93a.75.75 0 0 1-.927-.928l.929-3.25c.081-.286.235-.547.445-.758l8.61-8.609Zm.176 4.823L9.75 4.81l-6.286 6.287a.253.253 0 0 0-.064.108l-.558 1.953 1.953-.558a.253.253 0 0 0 .108-.064Zm1.238-3.763a.25.25 0 0 0-.354 0L10.811 3.75l1.439 1.44 1.263-1.263a.25.25 0 0 0 0-.354Z";
1120
1120
  var COMMENT_DISCUSSION_16_PATH = "M1.75 1h8.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 10.25 10H7.061l-2.574 2.573A1.458 1.458 0 0 1 2 11.543V10h-.25A1.75 1.75 0 0 1 0 8.25v-5.5C0 1.784.784 1 1.75 1ZM1.5 2.75v5.5c0 .138.112.25.25.25h1a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h3.5a.25.25 0 0 0 .25-.25v-5.5a.25.25 0 0 0-.25-.25h-8.5a.25.25 0 0 0-.25.25Zm13 2a.25.25 0 0 0-.25-.25h-.5a.75.75 0 0 1 0-1.5h.5c.966 0 1.75.784 1.75 1.75v5.5A1.75 1.75 0 0 1 14.25 12H14v1.543a1.458 1.458 0 0 1-2.487 1.03L9.22 12.28a.749.749 0 0 1 .326-1.275.749.749 0 0 1 .734.215l2.22 2.22v-2.19a.75.75 0 0 1 .75-.75h1a.25.25 0 0 0 .25-.25Z";
1121
1121
  var GRABBER_16_PATH = "M10 13h4v-2h-4v2Zm-8 0h4v-2H2v2Zm8-6h4V5h-4v2ZM2 7h4V5H2v2Zm8-6v2h4V1h-4ZM2 3h4V1H2v2Z";
1122
+ var KEBAB_16_PATH = "M8 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3ZM1.5 9a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Zm13 0a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z";
1122
1123
  var PULSE_16_PATH = "M6 2c.306 0 .582.187.696.471L10 10.731l1.304-3.26A.751.751 0 0 1 12 7h3.25a.75.75 0 0 1 0 1.5h-2.742l-1.812 4.528a.751.751 0 0 1-1.392 0L6 4.77 4.696 8.03A.75.75 0 0 1 4 8.5H.75a.75.75 0 0 1 0-1.5h2.742l1.812-4.529A.751.751 0 0 1 6 2Z";
1123
1124
  var MOON_16_PATH = "M9.598 1.591a.749.749 0 0 1 .785-.175 7.001 7.001 0 1 1-8.967 8.967.75.75 0 0 1 .961-.96 5.5 5.5 0 0 0 7.046-7.046.75.75 0 0 1 .175-.786Zm1.616 1.945a7 7 0 0 1-7.678 7.678 5.499 5.499 0 1 0 7.678-7.678Z";
1124
1125
  var QUESTION_16_PATH = "M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.92 6.085h.001a.749.749 0 1 1-1.342-.67c.169-.339.436-.701.849-.977C6.845 4.16 7.369 4 8 4a2.756 2.756 0 0 1 1.637.525c.503.377.863.965.863 1.725 0 .448-.115.83-.329 1.15-.205.307-.47.513-.692.662-.109.072-.22.138-.313.195l-.006.004a6.24 6.24 0 0 0-.26.16.952.952 0 0 0-.276.245.75.75 0 0 1-1.248-.832c.184-.264.42-.489.692-.661.103-.067.207-.132.313-.195l.007-.004c.1-.061.182-.11.258-.161a.969.969 0 0 0 .277-.245C8.96 6.514 9 6.427 9 6.25a.612.612 0 0 0-.262-.525A1.27 1.27 0 0 0 8 5.5c-.369 0-.595.09-.74.187a1.01 1.01 0 0 0-.34.398ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z";
@@ -1795,6 +1796,19 @@ Details: ${JSON.stringify(output)}` : "";
1795
1796
  lang: params.get("lang") || "en",
1796
1797
  section: params.get("section") || "overview"
1797
1798
  };
1799
+ case "/worktree": {
1800
+ const wt = params.get("wt") || "";
1801
+ const file = params.get("file") || "";
1802
+ const rawOrigin = params.get("origin");
1803
+ const origin = rawOrigin === "committed" || rawOrigin === "uncommitted" ? rawOrigin : void 0;
1804
+ return {
1805
+ screen: "worktree",
1806
+ ...wt ? { wt } : {},
1807
+ ...file ? { file } : {},
1808
+ ...origin ? { origin } : {},
1809
+ range
1810
+ };
1811
+ }
1798
1812
  case "/doctor":
1799
1813
  return {
1800
1814
  screen: "repo",
@@ -1878,6 +1892,14 @@ Details: ${JSON.stringify(output)}` : "";
1878
1892
  return "/file?path=" + encodeURIComponent(route.path) + "&ref=" + encodeURIComponent(route.ref || "worktree") + "&from=" + encodeURIComponent(route.range.from || "") + "&to=" + encodeURIComponent(route.range.to || "worktree") + (route.line ? `&line=${encodeURIComponent(formatLineTarget(route.line))}` : "") + (route.virtual === "off" ? "&virtual=off" : "");
1879
1893
  case "diff":
1880
1894
  return "/todif?from=" + encodeURIComponent(route.range.from || "") + "&to=" + encodeURIComponent(route.range.to || "worktree") + (route.path ? `&path=${encodeURIComponent(route.path)}` : "") + (route.line ? `&line=${encodeURIComponent(formatLineTarget(route.line))}` : "");
1895
+ case "worktree": {
1896
+ const params = new URLSearchParams();
1897
+ if (route.wt) params.set("wt", route.wt);
1898
+ if (route.file) params.set("file", route.file);
1899
+ if (route.file && route.origin) params.set("origin", route.origin);
1900
+ const qs = params.toString();
1901
+ return `/worktree${qs ? `?${qs}` : ""}`;
1902
+ }
1881
1903
  case "help": {
1882
1904
  const params = new URLSearchParams();
1883
1905
  if (route.lang && route.lang !== "en") params.set("lang", route.lang);
@@ -1937,8 +1959,8 @@ Details: ${JSON.stringify(output)}` : "";
1937
1959
  const qs = params.toString();
1938
1960
  return qs ? `${base2}?${qs}` : base2;
1939
1961
  }
1940
- function withDoctorOverlay(url, open) {
1941
- return withQueryParam(url, "doctor", open ? "open" : null);
1962
+ function withDoctorOverlay(url, open2) {
1963
+ return withQueryParam(url, "doctor", open2 ? "open" : null);
1942
1964
  }
1943
1965
  function parseToolsOverlay(search) {
1944
1966
  const raw = new URLSearchParams(search).get("tools");
@@ -7924,8 +7946,8 @@ Details: ${JSON.stringify(output)}` : "";
7924
7946
  compile(this);
7925
7947
  return this;
7926
7948
  }
7927
- this.__tlds__ = this.__tlds__.concat(list2).sort().filter(function(el, idx, arr) {
7928
- return el !== arr[idx - 1];
7949
+ this.__tlds__ = this.__tlds__.concat(list2).sort().filter(function(el2, idx, arr) {
7950
+ return el2 !== arr[idx - 1];
7929
7951
  }).reverse();
7930
7952
  compile(this);
7931
7953
  return this;
@@ -9165,8 +9187,8 @@ Details: ${JSON.stringify(output)}` : "";
9165
9187
  const markerRe = new RegExp(`^\\[!(${ALERT_TYPES.join("|")})\\]\\s*`, "i");
9166
9188
  let i2 = 0;
9167
9189
  while (i2 < state.tokens.length) {
9168
- const open = state.tokens[i2];
9169
- if (open.type !== "blockquote_open") {
9190
+ const open2 = state.tokens[i2];
9191
+ if (open2.type !== "blockquote_open") {
9170
9192
  i2++;
9171
9193
  continue;
9172
9194
  }
@@ -9191,7 +9213,7 @@ Details: ${JSON.stringify(output)}` : "";
9191
9213
  continue;
9192
9214
  }
9193
9215
  const type = match2[1].toLowerCase();
9194
- open.attrSet("class", `markdown-alert markdown-alert-${type}`);
9216
+ open2.attrSet("class", `markdown-alert markdown-alert-${type}`);
9195
9217
  const rest = first.content.slice(match2[0].length);
9196
9218
  if (rest) {
9197
9219
  first.content = rest;
@@ -9729,8 +9751,8 @@ ${frontmatter.yaml}
9729
9751
 
9730
9752
  // web-src/views/diff-line-select.ts
9731
9753
  var SELECTED_CLASS = "gdp-diff-line-selected";
9732
- function cardPath(el) {
9733
- return el.closest(".gdp-file-shell[data-path]")?.dataset.path || "";
9754
+ function cardPath(el2) {
9755
+ return el2.closest(".gdp-file-shell[data-path]")?.dataset.path || "";
9734
9756
  }
9735
9757
  function afterLineFromCell(cell) {
9736
9758
  const sideCell = cell.closest("td.d2h-code-side-linenumber");
@@ -10076,6 +10098,7 @@ ${frontmatter.yaml}
10076
10098
  const submit = document.createElement("button");
10077
10099
  submit.type = "button";
10078
10100
  submit.className = "gdp-btn gdp-btn-sm";
10101
+ if (opts.danger) submit.classList.add("gdp-dialog-danger");
10079
10102
  submit.textContent = opts.submitLabel ?? "Save";
10080
10103
  const error2 = document.createElement("div");
10081
10104
  error2.className = "gdp-dialog-error";
@@ -10218,10 +10241,10 @@ ${frontmatter.yaml}
10218
10241
  function updateDatabaseCaptureButton() {
10219
10242
  annotationCaptureDb.hidden = deps.getRoute().screen !== "database";
10220
10243
  }
10221
- function setAnnotationPanelOpen(open) {
10222
- annotationPanel.hidden = !open;
10223
- document.body.classList.toggle("annotation-panel-open", open);
10224
- if (open) {
10244
+ function setAnnotationPanelOpen(open2) {
10245
+ annotationPanel.hidden = !open2;
10246
+ document.body.classList.toggle("annotation-panel-open", open2);
10247
+ if (open2) {
10225
10248
  annotationPanelDismissed = false;
10226
10249
  const qhPanel = document.getElementById("query-history-panel");
10227
10250
  if (qhPanel) qhPanel.hidden = true;
@@ -10232,7 +10255,7 @@ ${frontmatter.yaml}
10232
10255
  updateActiveHighlights();
10233
10256
  syncInlineAnnotationActive();
10234
10257
  }
10235
- deps.setAnnotationPanelOpenState(open);
10258
+ deps.setAnnotationPanelOpenState(open2);
10236
10259
  syncSessionUrl();
10237
10260
  applyInlineAnnotations();
10238
10261
  }
@@ -10364,20 +10387,20 @@ ${frontmatter.yaml}
10364
10387
  }
10365
10388
  function applyDatabaseAnnotations(session) {
10366
10389
  if (databaseAnnotationsMounted) {
10367
- document.querySelectorAll(".gdp-db-annotation-strip").forEach((el) => {
10368
- el.remove();
10390
+ document.querySelectorAll(".gdp-db-annotation-strip").forEach((el2) => {
10391
+ el2.remove();
10369
10392
  });
10370
10393
  databaseAnnotationsMounted = false;
10371
10394
  }
10372
10395
  if (!session || deps.getRoute().screen !== "database") return;
10373
- const matches = session.entries.filter(databaseAnnotationMatchesRoute);
10374
- if (!matches.length) return;
10396
+ const matches2 = session.entries.filter(databaseAnnotationMatchesRoute);
10397
+ if (!matches2.length) return;
10375
10398
  const root = document.querySelector(".db-root");
10376
10399
  if (!root) return;
10377
10400
  const strip = document.createElement("section");
10378
10401
  strip.className = "gdp-db-annotation-strip";
10379
10402
  strip.setAttribute("aria-label", "Datastore annotations");
10380
- for (const entry of matches) {
10403
+ for (const entry of matches2) {
10381
10404
  strip.appendChild(
10382
10405
  buildDatabaseAnnotationBlock(entry, {
10383
10406
  index: session.entries.indexOf(entry),
@@ -10493,10 +10516,10 @@ ${frontmatter.yaml}
10493
10516
  function syncInlineAnnotationWidths() {
10494
10517
  document.querySelectorAll(".gdp-annotation-inline").forEach((box) => {
10495
10518
  let scroller = null;
10496
- for (let el = box.parentElement; el && el !== document.body; el = el.parentElement) {
10497
- const overflowX = getComputedStyle(el).overflowX;
10519
+ for (let el2 = box.parentElement; el2 && el2 !== document.body; el2 = el2.parentElement) {
10520
+ const overflowX = getComputedStyle(el2).overflowX;
10498
10521
  if (overflowX === "auto" || overflowX === "scroll") {
10499
- scroller = el;
10522
+ scroller = el2;
10500
10523
  break;
10501
10524
  }
10502
10525
  }
@@ -10695,8 +10718,8 @@ ${frontmatter.yaml}
10695
10718
  const head = annotationDetail.querySelector(
10696
10719
  ".annotation-detail-head"
10697
10720
  );
10698
- head?.querySelectorAll(".annotation-detail-head-action").forEach((el) => {
10699
- el.remove();
10721
+ head?.querySelectorAll(".annotation-detail-head-action").forEach((el2) => {
10722
+ el2.remove();
10700
10723
  });
10701
10724
  const body = $("#annotation-detail-body");
10702
10725
  body.replaceChildren();
@@ -10850,25 +10873,25 @@ ${frontmatter.yaml}
10850
10873
  const item = document.createElement("li");
10851
10874
  item.dataset.entryId = entry.id;
10852
10875
  item.classList.toggle("active", entry.id === activeAnnotationId);
10853
- const open = document.createElement("button");
10854
- open.type = "button";
10855
- open.className = "annotation-entry-open";
10876
+ const open2 = document.createElement("button");
10877
+ open2.type = "button";
10878
+ open2.className = "annotation-entry-open";
10856
10879
  const location2 = document.createElement("span");
10857
10880
  location2.className = "annotation-entry-location";
10858
10881
  location2.textContent = annotationLocationLabel(entry);
10859
10882
  const summary = document.createElement("span");
10860
10883
  summary.className = "annotation-entry-summary";
10861
10884
  summary.textContent = annotationEntrySummary(entry);
10862
- open.append(location2, summary);
10885
+ open2.append(location2, summary);
10863
10886
  const entryTimeLabel = annotationTimeLabel(entry.created_at);
10864
10887
  if (entryTimeLabel) {
10865
10888
  const time2 = document.createElement("span");
10866
10889
  time2.className = "annotation-entry-time";
10867
10890
  time2.textContent = entryTimeLabel;
10868
10891
  time2.title = entry.created_at;
10869
- open.appendChild(time2);
10892
+ open2.appendChild(time2);
10870
10893
  }
10871
- open.addEventListener("click", () => {
10894
+ open2.addEventListener("click", () => {
10872
10895
  void openAnnotationEntry(entry.id);
10873
10896
  });
10874
10897
  const remove = annotationIconButton(
@@ -10886,7 +10909,7 @@ ${frontmatter.yaml}
10886
10909
  if (!ok) return;
10887
10910
  void postAnnotationAction({ action: "delete", id: entry.id });
10888
10911
  });
10889
- item.append(open, remove);
10912
+ item.append(open2, remove);
10890
10913
  list2.appendChild(item);
10891
10914
  });
10892
10915
  sessionEl.appendChild(list2);
@@ -10894,13 +10917,13 @@ ${frontmatter.yaml}
10894
10917
  }
10895
10918
  }
10896
10919
  function updateActiveHighlights() {
10897
- annotationSessionsEl.querySelectorAll(".annotation-session").forEach((el) => {
10898
- el.classList.toggle("active", el.dataset.sessionId === activeSessionId);
10920
+ annotationSessionsEl.querySelectorAll(".annotation-session").forEach((el2) => {
10921
+ el2.classList.toggle("active", el2.dataset.sessionId === activeSessionId);
10899
10922
  });
10900
- annotationSessionsEl.querySelectorAll(".annotation-entries li").forEach((el) => {
10901
- el.classList.toggle(
10923
+ annotationSessionsEl.querySelectorAll(".annotation-entries li").forEach((el2) => {
10924
+ el2.classList.toggle(
10902
10925
  "active",
10903
- el.dataset.entryId === activeAnnotationId
10926
+ el2.dataset.entryId === activeAnnotationId
10904
10927
  );
10905
10928
  });
10906
10929
  }
@@ -10939,8 +10962,8 @@ ${frontmatter.yaml}
10939
10962
  const head = annotationDetail.querySelector(
10940
10963
  ".annotation-detail-head"
10941
10964
  );
10942
- head?.querySelectorAll(".annotation-detail-head-action").forEach((el) => {
10943
- el.remove();
10965
+ head?.querySelectorAll(".annotation-detail-head-action").forEach((el2) => {
10966
+ el2.remove();
10944
10967
  });
10945
10968
  const copyRef = createCopyRefButton(entry, "annotation-detail-head-action");
10946
10969
  const edit = annotationIconButton(
@@ -11532,8 +11555,8 @@ ${frontmatter.yaml}
11532
11555
  function createBlameView(deps) {
11533
11556
  let activeGeneration = 0;
11534
11557
  function cleanup() {
11535
- document.querySelectorAll(".gdp-standalone-blame").forEach((el) => {
11536
- el.remove();
11558
+ document.querySelectorAll(".gdp-standalone-blame").forEach((el2) => {
11559
+ el2.remove();
11537
11560
  });
11538
11561
  }
11539
11562
  function colourBarFor(commit, bin, binCount) {
@@ -13102,16 +13125,16 @@ ${frontmatter.yaml}
13102
13125
  }
13103
13126
 
13104
13127
  // web-src/views/database/pane-status.ts
13105
- function setPaneStatus(el, message, options = {}) {
13106
- el.innerHTML = "";
13128
+ function setPaneStatus(el2, message, options = {}) {
13129
+ el2.innerHTML = "";
13107
13130
  options.afterClear?.();
13108
13131
  const note = document.createElement("div");
13109
13132
  note.className = options.error ? "db-pane-error" : "db-pane-note";
13110
13133
  note.textContent = message;
13111
- el.appendChild(note);
13134
+ el2.appendChild(note);
13112
13135
  }
13113
- function setPaneEmpty(el, message, options = {}) {
13114
- el.innerHTML = "";
13136
+ function setPaneEmpty(el2, message, options = {}) {
13137
+ el2.innerHTML = "";
13115
13138
  const empty = document.createElement("div");
13116
13139
  empty.className = "db-pane-empty";
13117
13140
  const icon = document.createElement("div");
@@ -13127,7 +13150,7 @@ ${frontmatter.yaml}
13127
13150
  hint.textContent = options.hint;
13128
13151
  empty.appendChild(hint);
13129
13152
  }
13130
- el.appendChild(empty);
13153
+ el2.appendChild(empty);
13131
13154
  }
13132
13155
 
13133
13156
  // web-src/views/database/dynamodb-explorer.ts
@@ -14821,9 +14844,9 @@ ${frontmatter.yaml}
14821
14844
  }
14822
14845
  function createErDiagram(deps = {}) {
14823
14846
  const text3 = () => deps.getText?.() ?? dbText("en");
14824
- const el = document.createElement("div");
14825
- el.className = "db-er-diagram";
14826
- el.hidden = true;
14847
+ const el2 = document.createElement("div");
14848
+ el2.className = "db-er-diagram";
14849
+ el2.hidden = true;
14827
14850
  const toolbar = document.createElement("div");
14828
14851
  toolbar.className = "db-er-toolbar";
14829
14852
  const zoomIn = document.createElement("button");
@@ -14853,7 +14876,7 @@ ${frontmatter.yaml}
14853
14876
  });
14854
14877
  const container = viewport.container;
14855
14878
  const svgWrap = viewport.content;
14856
- el.append(toolbar, container);
14879
+ el2.append(toolbar, container);
14857
14880
  let lastMarkup = "";
14858
14881
  zoomIn.addEventListener("click", () => viewport.zoomIn());
14859
14882
  zoomOut.addEventListener("click", () => viewport.zoomOut());
@@ -14872,7 +14895,7 @@ ${frontmatter.yaml}
14872
14895
  }
14873
14896
  });
14874
14897
  async function render(schema, columnsMap) {
14875
- el.hidden = false;
14898
+ el2.hidden = false;
14876
14899
  svgWrap.innerHTML = "";
14877
14900
  viewport.reset();
14878
14901
  const tables = schema.tables.filter((t2) => t2.type === "table");
@@ -14898,7 +14921,7 @@ ${frontmatter.yaml}
14898
14921
  }
14899
14922
  }
14900
14923
  function clear() {
14901
- el.hidden = true;
14924
+ el2.hidden = true;
14902
14925
  svgWrap.innerHTML = "";
14903
14926
  lastMarkup = "";
14904
14927
  }
@@ -14914,14 +14937,14 @@ ${frontmatter.yaml}
14914
14937
  copyBtn.title = t2.copyMermaidTitle;
14915
14938
  if (copyBtn.textContent !== t2.copied) copyBtn.textContent = t2.copyMermaid;
14916
14939
  }
14917
- return { el, render, clear, dispose, localize };
14940
+ return { el: el2, render, clear, dispose, localize };
14918
14941
  }
14919
14942
 
14920
14943
  // web-src/views/database/global-search-view.ts
14921
14944
  function createGlobalSearchView(deps) {
14922
14945
  const text3 = () => deps.getText?.() ?? dbText("en");
14923
- const el = document.createElement("div");
14924
- el.className = "db-global-search";
14946
+ const el2 = document.createElement("div");
14947
+ el2.className = "db-global-search";
14925
14948
  const header = document.createElement("div");
14926
14949
  header.className = "db-global-search-header";
14927
14950
  const input2 = document.createElement("input");
@@ -14951,7 +14974,7 @@ ${frontmatter.yaml}
14951
14974
  progress.hidden = true;
14952
14975
  const results = document.createElement("div");
14953
14976
  results.className = "db-global-search-results";
14954
- el.append(header, optionsRow, progress, results);
14977
+ el2.append(header, optionsRow, progress, results);
14955
14978
  let currentJobId = null;
14956
14979
  let pollTimer = null;
14957
14980
  let disposed = false;
@@ -15147,7 +15170,7 @@ ${frontmatter.yaml}
15147
15170
  cancelBtn.textContent = t2.cancelButton;
15148
15171
  nonTextText.textContent = t2.includeNonText;
15149
15172
  }
15150
- return { el, setSearch, getSearch, dispose, localize };
15173
+ return { el: el2, setSearch, getSearch, dispose, localize };
15151
15174
  }
15152
15175
 
15153
15176
  // web-src/views/database/pref-toggle.ts
@@ -15196,8 +15219,8 @@ ${frontmatter.yaml}
15196
15219
  var MAX_HISTORY = 50;
15197
15220
  function createQueryEditor(callbacks) {
15198
15221
  const text3 = () => callbacks.getText?.() ?? dbText("en");
15199
- const el = document.createElement("div");
15200
- el.className = "db-query-editor";
15222
+ const el2 = document.createElement("div");
15223
+ el2.className = "db-query-editor";
15201
15224
  const inputArea = document.createElement("div");
15202
15225
  inputArea.className = "db-query-input";
15203
15226
  const editorWrap = document.createElement("div");
@@ -15275,7 +15298,7 @@ ${frontmatter.yaml}
15275
15298
  const resultArea = document.createElement("div");
15276
15299
  resultArea.className = "db-query-result";
15277
15300
  resultArea.hidden = true;
15278
- el.append(inputArea, resultArea);
15301
+ el2.append(inputArea, resultArea);
15279
15302
  async function run() {
15280
15303
  const sql = textarea.value.trim();
15281
15304
  if (!sql) return;
@@ -15510,7 +15533,7 @@ ${frontmatter.yaml}
15510
15533
  historyBtn.title = t2.localHistoryTitle;
15511
15534
  }
15512
15535
  return {
15513
- el,
15536
+ el: el2,
15514
15537
  focus,
15515
15538
  setSql,
15516
15539
  getSql,
@@ -15524,8 +15547,8 @@ ${frontmatter.yaml}
15524
15547
  // web-src/views/database/query-history-view.ts
15525
15548
  function createQueryHistoryView(callbacks) {
15526
15549
  const text3 = () => callbacks.getText?.() ?? dbText("en");
15527
- const el = document.createElement("div");
15528
- el.className = "db-query-history";
15550
+ const el2 = document.createElement("div");
15551
+ el2.className = "db-query-history";
15529
15552
  const toolbar = document.createElement("div");
15530
15553
  toolbar.className = "db-query-history-toolbar";
15531
15554
  const refreshBtn = document.createElement("button");
@@ -15559,7 +15582,7 @@ ${frontmatter.yaml}
15559
15582
  detailPlaceholder.textContent = text3().history.selectPlaceholder;
15560
15583
  detailCol.appendChild(detailPlaceholder);
15561
15584
  body.append(listCol, detailCol);
15562
- el.append(toolbar, body);
15585
+ el2.append(toolbar, body);
15563
15586
  let entries = [];
15564
15587
  const expandedIds = /* @__PURE__ */ new Set();
15565
15588
  let clearConfirmTimer = null;
@@ -15967,7 +15990,7 @@ ${frontmatter.yaml}
15967
15990
  }
15968
15991
  }
15969
15992
  }
15970
- return { el, refresh, clear, localize };
15993
+ return { el: el2, refresh, clear, localize };
15971
15994
  }
15972
15995
  function formatTime(iso) {
15973
15996
  try {
@@ -15983,17 +16006,17 @@ ${frontmatter.yaml}
15983
16006
  function isBinaryItem(item) {
15984
16007
  return typeof item === "object" && item !== null && "binaryBase64" in item;
15985
16008
  }
15986
- function renderItemInto(el, item, binaryBadge) {
15987
- el.textContent = "";
16009
+ function renderItemInto(el2, item, binaryBadge) {
16010
+ el2.textContent = "";
15988
16011
  if (isBinaryItem(item)) {
15989
16012
  const badge = document.createElement("span");
15990
16013
  badge.className = "redis-binary-badge";
15991
16014
  badge.textContent = binaryBadge;
15992
- el.appendChild(badge);
15993
- el.appendChild(document.createTextNode(item.binaryBase64));
16015
+ el2.appendChild(badge);
16016
+ el2.appendChild(document.createTextNode(item.binaryBase64));
15994
16017
  return;
15995
16018
  }
15996
- el.textContent = item;
16019
+ el2.textContent = item;
15997
16020
  }
15998
16021
  function createRedisExplorer(callbacks = {}) {
15999
16022
  const text3 = () => (callbacks.getText?.() ?? dbText("en")).explorer;
@@ -17207,8 +17230,8 @@ ${frontmatter.yaml}
17207
17230
  function isAbortError(err) {
17208
17231
  return err instanceof DOMException && err.name === "AbortError";
17209
17232
  }
17210
- function setExplorerFolderIcon(el, collapsed) {
17211
- el.innerHTML = iconSvg(
17233
+ function setExplorerFolderIcon(el2, collapsed) {
17234
+ el2.innerHTML = iconSvg(
17212
17235
  collapsed ? "octicon-file-directory-fill" : "octicon-file-directory-open-fill",
17213
17236
  collapsed ? FOLDER_ICON_PATHS.closed : FOLDER_ICON_PATHS.open
17214
17237
  );
@@ -17767,12 +17790,12 @@ ${frontmatter.yaml}
17767
17790
  actions.className = "s3-preview-actions";
17768
17791
  if (currentDbId && currentBucket) {
17769
17792
  const rawUrl = buildS3RawUrl(currentDbId, currentBucket, object.key);
17770
- const open = document.createElement("a");
17771
- open.className = "db-btn db-btn-sm";
17772
- open.href = rawUrl;
17773
- open.target = "_blank";
17774
- open.rel = "noreferrer";
17775
- open.textContent = text3().openRaw;
17793
+ const open2 = document.createElement("a");
17794
+ open2.className = "db-btn db-btn-sm";
17795
+ open2.href = rawUrl;
17796
+ open2.target = "_blank";
17797
+ open2.rel = "noreferrer";
17798
+ open2.textContent = text3().openRaw;
17776
17799
  const download = document.createElement("a");
17777
17800
  download.className = "db-btn db-btn-sm";
17778
17801
  download.href = rawUrl;
@@ -17795,7 +17818,7 @@ ${frontmatter.yaml}
17795
17818
  copy.textContent = text3().copyFailed;
17796
17819
  }
17797
17820
  });
17798
- actions.append(open, download, copy);
17821
+ actions.append(open2, download, copy);
17799
17822
  if (sourceDisplayKind(object.key) === "text") {
17800
17823
  const editBtn = mkBtn(tCommon().edit, "db-btn db-btn-sm");
17801
17824
  editBtn.addEventListener("click", () => void startObjectEdit(object));
@@ -17922,8 +17945,8 @@ ${frontmatter.yaml}
17922
17945
  function indentPad(depth) {
17923
17946
  return `${12 + depth * 14}px`;
17924
17947
  }
17925
- function setExplorerChevron(el) {
17926
- el.innerHTML = `<svg class="octicon octicon-chevron-down" viewBox="0 0 12 12" width="12" height="12" fill="currentColor" aria-hidden="true"><path fill="currentColor" d="${CHEVRON_DOWN_12_PATH}"></path></svg>`;
17948
+ function setExplorerChevron(el2) {
17949
+ el2.innerHTML = `<svg class="octicon octicon-chevron-down" viewBox="0 0 12 12" width="12" height="12" fill="currentColor" aria-hidden="true"><path fill="currentColor" d="${CHEVRON_DOWN_12_PATH}"></path></svg>`;
17927
17950
  }
17928
17951
  function resetExplorer() {
17929
17952
  explorerAbort?.abort();
@@ -17951,11 +17974,11 @@ ${frontmatter.yaml}
17951
17974
  return await res.json();
17952
17975
  }
17953
17976
  function makeTreeMessageRow(cls, depth, text4) {
17954
- const el = document.createElement("div");
17955
- el.className = cls;
17956
- el.style.setProperty("--lvl-pad", indentPad(depth));
17957
- el.textContent = text4;
17958
- return el;
17977
+ const el2 = document.createElement("div");
17978
+ el2.className = cls;
17979
+ el2.style.setProperty("--lvl-pad", indentPad(depth));
17980
+ el2.textContent = text4;
17981
+ return el2;
17959
17982
  }
17960
17983
  function createExplorerFileRow(object, depth) {
17961
17984
  objectsByKey.set(object.key, object);
@@ -18422,9 +18445,9 @@ ${frontmatter.yaml}
18422
18445
  // web-src/views/database/schema-view.ts
18423
18446
  function createSchemaView(deps = {}) {
18424
18447
  const text3 = () => deps.getText?.() ?? dbText("en");
18425
- const el = document.createElement("div");
18426
- el.className = "db-schema-view";
18427
- el.hidden = true;
18448
+ const el2 = document.createElement("div");
18449
+ el2.className = "db-schema-view";
18450
+ el2.hidden = true;
18428
18451
  let refreshBusy = false;
18429
18452
  let refreshBtn = null;
18430
18453
  let refreshLabel = null;
@@ -18446,8 +18469,8 @@ ${frontmatter.yaml}
18446
18469
  function render(table2, columns, indexes, extra) {
18447
18470
  lastArgs = { table: table2, columns, indexes, extra };
18448
18471
  const t2 = text3().schema;
18449
- el.hidden = false;
18450
- el.innerHTML = "";
18472
+ el2.hidden = false;
18473
+ el2.innerHTML = "";
18451
18474
  const header = document.createElement("div");
18452
18475
  header.className = "db-schema-header";
18453
18476
  const headerTitle = document.createElement("span");
@@ -18473,11 +18496,11 @@ ${frontmatter.yaml}
18473
18496
  refreshBtn = null;
18474
18497
  refreshLabel = null;
18475
18498
  }
18476
- el.appendChild(header);
18499
+ el2.appendChild(header);
18477
18500
  const colSectionHeader = document.createElement("div");
18478
18501
  colSectionHeader.className = "db-schema-section-header";
18479
18502
  colSectionHeader.textContent = t2.columns;
18480
- el.appendChild(colSectionHeader);
18503
+ el2.appendChild(colSectionHeader);
18481
18504
  const colTable = document.createElement("table");
18482
18505
  colTable.className = "db-schema-table";
18483
18506
  const thead = document.createElement("thead");
@@ -18520,13 +18543,13 @@ ${frontmatter.yaml}
18520
18543
  tbody.appendChild(tr);
18521
18544
  }
18522
18545
  colTable.append(thead, tbody);
18523
- el.appendChild(colTable);
18546
+ el2.appendChild(colTable);
18524
18547
  const fks = extra?.foreignKeys?.filter((fk) => fk.fromTable === table2);
18525
18548
  if (fks && fks.length > 0) {
18526
18549
  const fkHeader = document.createElement("div");
18527
18550
  fkHeader.className = "db-schema-section-header";
18528
18551
  fkHeader.textContent = t2.foreignKeys;
18529
- el.appendChild(fkHeader);
18552
+ el2.appendChild(fkHeader);
18530
18553
  const fkTable = document.createElement("table");
18531
18554
  fkTable.className = "db-schema-table";
18532
18555
  const fkThead = document.createElement("thead");
@@ -18550,14 +18573,14 @@ ${frontmatter.yaml}
18550
18573
  fkTbody.appendChild(tr);
18551
18574
  }
18552
18575
  fkTable.append(fkThead, fkTbody);
18553
- el.appendChild(fkTable);
18576
+ el2.appendChild(fkTable);
18554
18577
  }
18555
18578
  const tableIndexes = indexes.filter((idx) => idx.table === table2);
18556
18579
  if (tableIndexes.length > 0) {
18557
18580
  const idxHeader = document.createElement("div");
18558
18581
  idxHeader.className = "db-schema-section-header";
18559
18582
  idxHeader.textContent = t2.indexes;
18560
- el.appendChild(idxHeader);
18583
+ el2.appendChild(idxHeader);
18561
18584
  const idxTable = document.createElement("table");
18562
18585
  idxTable.className = "db-schema-table";
18563
18586
  const idxThead = document.createElement("thead");
@@ -18581,14 +18604,14 @@ ${frontmatter.yaml}
18581
18604
  idxTbody.appendChild(tr);
18582
18605
  }
18583
18606
  idxTable.append(idxThead, idxTbody);
18584
- el.appendChild(idxTable);
18607
+ el2.appendChild(idxTable);
18585
18608
  }
18586
18609
  const triggers = extra?.triggers;
18587
18610
  if (triggers && triggers.length > 0) {
18588
18611
  const trigHeader = document.createElement("div");
18589
18612
  trigHeader.className = "db-schema-section-header";
18590
18613
  trigHeader.textContent = t2.triggers;
18591
- el.appendChild(trigHeader);
18614
+ el2.appendChild(trigHeader);
18592
18615
  for (const trig of triggers) {
18593
18616
  const trigBlock = document.createElement("div");
18594
18617
  trigBlock.className = "db-schema-trigger-block";
@@ -18599,7 +18622,7 @@ ${frontmatter.yaml}
18599
18622
  trigPre.className = "db-schema-ddl-pre";
18600
18623
  trigPre.textContent = trig.sql;
18601
18624
  trigBlock.append(trigName, trigPre);
18602
- el.appendChild(trigBlock);
18625
+ el2.appendChild(trigBlock);
18603
18626
  }
18604
18627
  }
18605
18628
  const ddl = extra?.ddl;
@@ -18607,7 +18630,7 @@ ${frontmatter.yaml}
18607
18630
  const ddlHeader = document.createElement("div");
18608
18631
  ddlHeader.className = "db-schema-section-header";
18609
18632
  ddlHeader.textContent = t2.ddl;
18610
- el.appendChild(ddlHeader);
18633
+ el2.appendChild(ddlHeader);
18611
18634
  const ddlWrap = document.createElement("div");
18612
18635
  ddlWrap.className = "db-schema-ddl-wrap";
18613
18636
  const copyBtn = document.createElement("button");
@@ -18630,22 +18653,22 @@ ${frontmatter.yaml}
18630
18653
  ddlPre.className = "db-schema-ddl-pre";
18631
18654
  ddlPre.textContent = ddl;
18632
18655
  ddlWrap.append(copyBtn, ddlPre);
18633
- el.appendChild(ddlWrap);
18656
+ el2.appendChild(ddlWrap);
18634
18657
  }
18635
18658
  }
18636
18659
  function clear() {
18637
- el.hidden = true;
18638
- el.innerHTML = "";
18660
+ el2.hidden = true;
18661
+ el2.innerHTML = "";
18639
18662
  lastArgs = null;
18640
18663
  refreshBtn = null;
18641
18664
  refreshLabel = null;
18642
18665
  refreshBusy = false;
18643
18666
  }
18644
18667
  function localize() {
18645
- if (!lastArgs || el.hidden) return;
18668
+ if (!lastArgs || el2.hidden) return;
18646
18669
  render(lastArgs.table, lastArgs.columns, lastArgs.indexes, lastArgs.extra);
18647
18670
  }
18648
- return { el, render, clear, localize, setRefreshBusy };
18671
+ return { el: el2, render, clear, localize, setRefreshBusy };
18649
18672
  }
18650
18673
 
18651
18674
  // web-src/views/database/session-log.ts
@@ -18688,8 +18711,8 @@ ${frontmatter.yaml}
18688
18711
  // web-src/views/database/session-log-view.ts
18689
18712
  function createSessionLogView(callbacks) {
18690
18713
  const text3 = () => callbacks.getText?.() ?? dbText("en");
18691
- const el = document.createElement("div");
18692
- el.className = "db-session-log";
18714
+ const el2 = document.createElement("div");
18715
+ el2.className = "db-session-log";
18693
18716
  const toolbar = document.createElement("div");
18694
18717
  toolbar.className = "db-session-log-toolbar";
18695
18718
  const followBtn = document.createElement("button");
@@ -18718,7 +18741,7 @@ ${frontmatter.yaml}
18718
18741
  placeholder.textContent = text3().sessionLog.selectPlaceholder;
18719
18742
  detailCol.appendChild(placeholder);
18720
18743
  body.append(listCol, detailCol);
18721
- el.append(toolbar, body);
18744
+ el2.append(toolbar, body);
18722
18745
  let selectedId = null;
18723
18746
  const rowById = /* @__PURE__ */ new Map();
18724
18747
  let autoFollow = true;
@@ -18906,7 +18929,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
18906
18929
  placeholder.textContent = text3().sessionLog.selectPlaceholder;
18907
18930
  render();
18908
18931
  }
18909
- return { el, clear, localize };
18932
+ return { el: el2, clear, localize };
18910
18933
  }
18911
18934
  function formatTime2(timestamp) {
18912
18935
  const d2 = new Date(timestamp);
@@ -18944,8 +18967,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
18944
18967
  const note = s2.note ? ` — ${s2.note}` : "";
18945
18968
  return text3().snapshot.label(date, s2.tables.length, note);
18946
18969
  };
18947
- const el = document.createElement("div");
18948
- el.className = "db-snapshot-view";
18970
+ const el2 = document.createElement("div");
18971
+ el2.className = "db-snapshot-view";
18949
18972
  const guide = document.createElement("div");
18950
18973
  guide.className = "db-snapshot-guide";
18951
18974
  const guideTitle = document.createElement("div");
@@ -19039,7 +19062,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
19039
19062
  rightPane.className = "db-snapshot-right-pane";
19040
19063
  splitContainer.append(leftPane, rightPane);
19041
19064
  mainArea.appendChild(splitContainer);
19042
- el.append(guide, toolbar, progressArea, tableSelector, mainArea);
19065
+ el2.append(guide, toolbar, progressArea, tableSelector, mainArea);
19043
19066
  let snapshots = [];
19044
19067
  let currentDiff = null;
19045
19068
  let disposed = false;
@@ -19717,8 +19740,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
19717
19740
  threshold: 0
19718
19741
  }
19719
19742
  );
19720
- for (const el2 of section2.querySelectorAll(".db-snapshot-diff-table")) {
19721
- observer.observe(el2);
19743
+ for (const el3 of section2.querySelectorAll(".db-snapshot-diff-table")) {
19744
+ observer.observe(el3);
19722
19745
  }
19723
19746
  section2.__tocObserver = observer;
19724
19747
  rightPane.appendChild(section2);
@@ -19877,7 +19900,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
19877
19900
  }
19878
19901
  }
19879
19902
  async function editNote(snapshotId, currentNote) {
19880
- const existing = el.querySelector(".db-snapshot-inline-dialog");
19903
+ const existing = el2.querySelector(".db-snapshot-inline-dialog");
19881
19904
  if (existing) existing.remove();
19882
19905
  const dialog = document.createElement("div");
19883
19906
  dialog.className = "db-snapshot-inline-dialog";
@@ -19911,7 +19934,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
19911
19934
  });
19912
19935
  dialog.append(input2, saveBtn, cancelDlgBtn);
19913
19936
  const item = Array.from(
19914
- el.querySelectorAll(".db-snapshot-item")
19937
+ el2.querySelectorAll(".db-snapshot-item")
19915
19938
  ).find((node) => node.dataset.snapshotId === snapshotId);
19916
19939
  if (item) {
19917
19940
  item.after(dialog);
@@ -20040,7 +20063,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
20040
20063
  await showDiffInline(target.before, target.after);
20041
20064
  }
20042
20065
  return {
20043
- el,
20066
+ el: el2,
20044
20067
  refresh,
20045
20068
  handleSse,
20046
20069
  dispose,
@@ -20067,8 +20090,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
20067
20090
  function createTableGrid(callbacks, options = {}) {
20068
20091
  const embedded = options.embedded === true;
20069
20092
  const text3 = () => callbacks.getText?.() ?? dbText("en");
20070
- const el = document.createElement("div");
20071
- el.className = "db-grid";
20093
+ const el2 = document.createElement("div");
20094
+ el2.className = "db-grid";
20072
20095
  const filterBar = document.createElement("div");
20073
20096
  filterBar.className = "db-grid-filter-bar";
20074
20097
  const filterIcon = document.createElement("span");
@@ -20243,9 +20266,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
20243
20266
  detailResize.addEventListener("mousedown", startDetailResize);
20244
20267
  detailPanel.appendChild(detailResize);
20245
20268
  viewport.append(spacer, body, filteredEmpty);
20246
- el.append(filterBar, headerWrap, filterRowWrap, viewport, detailPanel);
20269
+ el2.append(filterBar, headerWrap, filterRowWrap, viewport, detailPanel);
20247
20270
  function panelMaxHeight() {
20248
- const containerH = el.clientHeight || window.innerHeight;
20271
+ const containerH = el2.clientHeight || window.innerHeight;
20249
20272
  return Math.max(
20250
20273
  DETAIL_PANEL_MIN_HEIGHT + 1,
20251
20274
  containerH - PANEL_MAX_RESERVE
@@ -20383,7 +20406,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
20383
20406
  relatedPanel.className = "db-related-panel";
20384
20407
  relatedPanel.hidden = true;
20385
20408
  relatedPanel.style.height = `${relatedHeight}px`;
20386
- el.appendChild(relatedPanel);
20409
+ el2.appendChild(relatedPanel);
20387
20410
  }
20388
20411
  const colWidths = /* @__PURE__ */ new Map();
20389
20412
  let activeResize = null;
@@ -21611,7 +21634,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
21611
21634
  if (!statusEl) {
21612
21635
  statusEl = document.createElement("div");
21613
21636
  statusEl.className = "db-grid-status";
21614
- el.appendChild(statusEl);
21637
+ el2.appendChild(statusEl);
21615
21638
  }
21616
21639
  const t2 = text3().grid;
21617
21640
  const parts = [t2.statusRows(totalRows.toLocaleString())];
@@ -21636,7 +21659,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
21636
21659
  statusEl = document.createElement("div");
21637
21660
  statusEl.className = "db-grid-status db-pane-error";
21638
21661
  statusEl.textContent = message;
21639
- el.appendChild(statusEl);
21662
+ el2.appendChild(statusEl);
21640
21663
  }
21641
21664
  function load(table2, initialData) {
21642
21665
  clear();
@@ -21857,12 +21880,12 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
21857
21880
  discardBtn.disabled = count === 0;
21858
21881
  notifyEditableIfChanged();
21859
21882
  }
21860
- function setControlVisibility(el2, visible) {
21861
- el2.style.visibility = visible ? "" : "hidden";
21862
- if ("tabIndex" in el2) {
21863
- el2.tabIndex = visible ? 0 : -1;
21883
+ function setControlVisibility(el3, visible) {
21884
+ el3.style.visibility = visible ? "" : "hidden";
21885
+ if ("tabIndex" in el3) {
21886
+ el3.tabIndex = visible ? 0 : -1;
21864
21887
  }
21865
- el2.setAttribute("aria-hidden", visible ? "false" : "true");
21888
+ el3.setAttribute("aria-hidden", visible ? "false" : "true");
21866
21889
  }
21867
21890
  const editableListeners = /* @__PURE__ */ new Set();
21868
21891
  const editModeListeners = /* @__PURE__ */ new Set();
@@ -22018,7 +22041,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22018
22041
  embeddedGrid?.refreshForeignKeys();
22019
22042
  }
22020
22043
  return {
22021
- el,
22044
+ el: el2,
22022
22045
  load,
22023
22046
  refresh: refreshCurrentTable,
22024
22047
  showError,
@@ -22078,9 +22101,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22078
22101
  filterClear.innerHTML = iconSvg("octicon-x", X_16_PATH);
22079
22102
  filterClear.hidden = true;
22080
22103
  filterWrap.append(filterInput, filterClear);
22081
- const el = document.createElement("div");
22082
- el.className = "db-table-list";
22083
- wrapper.append(filterWrap, el);
22104
+ const el2 = document.createElement("div");
22105
+ el2.className = "db-table-list";
22106
+ wrapper.append(filterWrap, el2);
22084
22107
  let activeTable = null;
22085
22108
  let allTables = [];
22086
22109
  const expandedTables = /* @__PURE__ */ new Set();
@@ -22089,7 +22112,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22089
22112
  let contextMenuClick = null;
22090
22113
  let contextMenuKeyDown = null;
22091
22114
  let contextMenuTimer = null;
22092
- function closeContextMenu() {
22115
+ function closeContextMenu2() {
22093
22116
  if (contextMenuTimer) {
22094
22117
  clearTimeout(contextMenuTimer);
22095
22118
  contextMenuTimer = null;
@@ -22107,9 +22130,9 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22107
22130
  contextMenu = null;
22108
22131
  }
22109
22132
  }
22110
- function showContextMenu(e2, tableName) {
22133
+ function showContextMenu2(e2, tableName) {
22111
22134
  e2.preventDefault();
22112
- closeContextMenu();
22135
+ closeContextMenu2();
22113
22136
  const menu = document.createElement("div");
22114
22137
  menu.className = "db-context-menu";
22115
22138
  menu.style.position = "absolute";
@@ -22150,7 +22173,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22150
22173
  row.textContent = item.label;
22151
22174
  row.addEventListener("click", () => {
22152
22175
  item.action();
22153
- closeContextMenu();
22176
+ closeContextMenu2();
22154
22177
  });
22155
22178
  menu.appendChild(row);
22156
22179
  }
@@ -22158,13 +22181,13 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22158
22181
  contextMenu = menu;
22159
22182
  const onDocClick = (ev) => {
22160
22183
  if (!menu.contains(ev.target)) {
22161
- closeContextMenu();
22184
+ closeContextMenu2();
22162
22185
  }
22163
22186
  };
22164
22187
  const onKeyDown = (ev) => {
22165
22188
  if (isImeComposing(ev)) return;
22166
22189
  if (ev.key === "Escape") {
22167
- closeContextMenu();
22190
+ closeContextMenu2();
22168
22191
  }
22169
22192
  };
22170
22193
  contextMenuClick = onDocClick;
@@ -22246,7 +22269,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22246
22269
  filterInput.focus();
22247
22270
  }
22248
22271
  function renderFiltered(tables, filter) {
22249
- el.innerHTML = "";
22272
+ el2.innerHTML = "";
22250
22273
  syncFilterClearButton();
22251
22274
  const filtered = filter ? tables.filter(
22252
22275
  (t2) => t2.name.toLowerCase().includes(filter.toLowerCase())
@@ -22268,7 +22291,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22268
22291
  actions.appendChild(clear);
22269
22292
  empty.appendChild(actions);
22270
22293
  }
22271
- el.appendChild(empty);
22294
+ el2.appendChild(empty);
22272
22295
  return;
22273
22296
  }
22274
22297
  const groups = { table: [], view: [] };
@@ -22280,7 +22303,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22280
22303
  const header = document.createElement("div");
22281
22304
  header.className = "db-table-group-header";
22282
22305
  header.textContent = type === "view" ? "Views" : "Tables";
22283
- el.appendChild(header);
22306
+ el2.appendChild(header);
22284
22307
  for (const table2 of items) {
22285
22308
  const node = document.createElement("div");
22286
22309
  node.className = "db-table-node";
@@ -22329,10 +22352,10 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22329
22352
  );
22330
22353
  row.addEventListener(
22331
22354
  "contextmenu",
22332
- (e2) => showContextMenu(e2, table2.name)
22355
+ (e2) => showContextMenu2(e2, table2.name)
22333
22356
  );
22334
22357
  node.append(row, children);
22335
- el.appendChild(node);
22358
+ el2.appendChild(node);
22336
22359
  }
22337
22360
  }
22338
22361
  }
@@ -22345,7 +22368,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22345
22368
  }
22346
22369
  columnCache.clear();
22347
22370
  activeTable = null;
22348
- closeContextMenu();
22371
+ closeContextMenu2();
22349
22372
  filterInput.value = "";
22350
22373
  renderFiltered(tables, "");
22351
22374
  }
@@ -22356,7 +22379,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22356
22379
  filterClear.addEventListener("click", clearFilter);
22357
22380
  function setActive(table2) {
22358
22381
  activeTable = table2;
22359
- el.querySelectorAll(".db-table-item").forEach((item) => {
22382
+ el2.querySelectorAll(".db-table-item").forEach((item) => {
22360
22383
  item.classList.toggle("active", item.dataset.table === table2);
22361
22384
  });
22362
22385
  }
@@ -22364,7 +22387,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22364
22387
  allTables = allTables.map(
22365
22388
  (entry) => entry.name === table2 ? { ...entry, rowCount } : entry
22366
22389
  );
22367
- for (const node of el.querySelectorAll(".db-table-node")) {
22390
+ for (const node of el2.querySelectorAll(".db-table-node")) {
22368
22391
  if (node.dataset.table !== table2) continue;
22369
22392
  const count = node.querySelector(".db-table-count");
22370
22393
  if (count)
@@ -22372,7 +22395,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
22372
22395
  }
22373
22396
  }
22374
22397
  function dispose() {
22375
- closeContextMenu();
22398
+ closeContextMenu2();
22376
22399
  allTables = [];
22377
22400
  expandedTables.clear();
22378
22401
  columnCache.clear();
@@ -25234,11 +25257,11 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25234
25257
  return !!text3 && !/\S/.test(text3);
25235
25258
  }
25236
25259
  function suppressWhitespaceOnlyInlineHighlights(root) {
25237
- root.querySelectorAll("ins, del").forEach((el) => {
25238
- if (!isWhitespaceOnlyInlineHighlight(el.textContent)) return;
25239
- const parent = el.parentNode;
25260
+ root.querySelectorAll("ins, del").forEach((el2) => {
25261
+ if (!isWhitespaceOnlyInlineHighlight(el2.textContent)) return;
25262
+ const parent = el2.parentNode;
25240
25263
  if (!parent) return;
25241
- parent.replaceChild(document.createTextNode(el.textContent || ""), el);
25264
+ parent.replaceChild(document.createTextNode(el2.textContent || ""), el2);
25242
25265
  });
25243
25266
  }
25244
25267
 
@@ -25365,12 +25388,12 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25365
25388
  button.innerHTML = expanded ? iconSvg("octicon-fold", COLLAPSE_ALL_16_PATHS) : iconSvg("octicon-unfold", EXPAND_ALL_16_PATHS);
25366
25389
  }
25367
25390
  function setProjectBranch(branch) {
25368
- const el = document.querySelector("#project-branch");
25369
- if (!el) return;
25370
- el.hidden = !branch;
25371
- const name = el.querySelector(".project-branch-name");
25391
+ const el2 = document.querySelector("#project-branch");
25392
+ if (!el2) return;
25393
+ el2.hidden = !branch;
25394
+ const name = el2.querySelector(".project-branch-name");
25372
25395
  if (name) name.textContent = branch;
25373
- el.title = branch ? `Current branch: ${branch}` : "";
25396
+ el2.title = branch ? `Current branch: ${branch}` : "";
25374
25397
  }
25375
25398
  let metaFilesForViewedProgress = [];
25376
25399
  function viewedProgressFor(files) {
@@ -25487,36 +25510,36 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25487
25510
  return true;
25488
25511
  }
25489
25512
  function renderMeta(meta) {
25490
- const el = $("#meta");
25513
+ const el2 = $("#meta");
25491
25514
  if (!meta) {
25492
- el.textContent = "";
25515
+ el2.textContent = "";
25493
25516
  metaFilesForViewedProgress = [];
25494
25517
  return;
25495
25518
  }
25496
25519
  setProjectName(meta.project || "");
25497
25520
  setProjectBranch(meta.branch || "");
25498
25521
  metaFilesForViewedProgress = meta.files || [];
25499
- el.innerHTML = "";
25522
+ el2.innerHTML = "";
25500
25523
  const text3 = diffText();
25501
25524
  if (meta.error) {
25502
25525
  const error2 = document.createElement("span");
25503
25526
  error2.className = "chip chip-error";
25504
25527
  error2.textContent = meta.error;
25505
- el.appendChild(error2);
25528
+ el2.appendChild(error2);
25506
25529
  }
25507
25530
  if (meta.totals) {
25508
25531
  const files = document.createElement("span");
25509
25532
  files.className = "chip chip-files";
25510
25533
  files.textContent = text3.files(meta.totals.files);
25511
- el.appendChild(files);
25534
+ el2.appendChild(files);
25512
25535
  const add2 = document.createElement("span");
25513
25536
  add2.className = "chip chip-add";
25514
25537
  add2.textContent = `+${meta.totals.additions}`;
25515
- el.appendChild(add2);
25538
+ el2.appendChild(add2);
25516
25539
  const del = document.createElement("span");
25517
25540
  del.className = "chip chip-del";
25518
25541
  del.textContent = `−${meta.totals.deletions}`;
25519
- el.appendChild(del);
25542
+ el2.appendChild(del);
25520
25543
  }
25521
25544
  const kinds = summarizeDiffFileKinds(meta.files);
25522
25545
  const kindChip = (className, label, count) => {
@@ -25524,7 +25547,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25524
25547
  const chip = document.createElement("span");
25525
25548
  chip.className = `chip ${className}`;
25526
25549
  chip.textContent = `${count} ${label}`;
25527
- el.appendChild(chip);
25550
+ el2.appendChild(chip);
25528
25551
  };
25529
25552
  kindChip("chip-added", text3.kindAdded, kinds.added);
25530
25553
  kindChip("chip-deleted", text3.kindDeleted, kinds.deleted);
@@ -25542,7 +25565,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25542
25565
  viewedProgress.viewed,
25543
25566
  viewedProgress.total
25544
25567
  );
25545
- el.appendChild(viewed);
25568
+ el2.appendChild(viewed);
25546
25569
  const nextUnviewed = document.createElement("button");
25547
25570
  nextUnviewed.type = "button";
25548
25571
  nextUnviewed.className = "chip chip-next-unviewed";
@@ -25553,7 +25576,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25553
25576
  nextUnviewed.addEventListener("click", () => {
25554
25577
  scrollToNextUnviewedFile();
25555
25578
  });
25556
- el.appendChild(nextUnviewed);
25579
+ el2.appendChild(nextUnviewed);
25557
25580
  }
25558
25581
  const u2 = document.createElement("span");
25559
25582
  u2.className = "chip chip-updated";
@@ -25561,7 +25584,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25561
25584
  u2.textContent = text3.updated(
25562
25585
  (/* @__PURE__ */ new Date()).toLocaleTimeString([], { hour12: false })
25563
25586
  );
25564
- el.appendChild(u2);
25587
+ el2.appendChild(u2);
25565
25588
  }
25566
25589
  let SUPPRESS_SPY_UNTIL = 0;
25567
25590
  function prefetchByPath(path) {
@@ -25683,17 +25706,17 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25683
25706
  LOAD_QUEUE.length = 0;
25684
25707
  ACTIVE_LOADS = 0;
25685
25708
  }
25686
- function fileKey(f2) {
25709
+ function fileKey2(f2) {
25687
25710
  return f2.key || f2.path;
25688
25711
  }
25689
25712
  function computeListSignature(files) {
25690
25713
  return files.map(
25691
- (f2) => `${fileKey(f2)}\0${f2.path}\0${f2.old_path || ""}\0${f2.status || "M"}`
25714
+ (f2) => `${fileKey2(f2)}\0${f2.path}\0${f2.old_path || ""}\0${f2.status || "M"}`
25692
25715
  ).join("\n");
25693
25716
  }
25694
25717
  function computeCardSignature(f2) {
25695
25718
  return [
25696
- fileKey(f2),
25719
+ fileKey2(f2),
25697
25720
  f2.status || "M",
25698
25721
  f2.additions || 0,
25699
25722
  f2.deletions || 0,
@@ -25770,7 +25793,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25770
25793
  const tmp = createPlaceholder(file);
25771
25794
  while (tmp.firstChild) card.appendChild(tmp.firstChild);
25772
25795
  card.dataset.path = file.path;
25773
- card.dataset.key = fileKey(file);
25796
+ card.dataset.key = fileKey2(file);
25774
25797
  card.dataset.sizeClass = file.size_class || "small";
25775
25798
  card.dataset.status = file.status || "M";
25776
25799
  card.dataset.reqId = String(++CLIENT_REQ_SEQ);
@@ -25793,7 +25816,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25793
25816
  renderMeta(meta);
25794
25817
  const target = getDiffRoot?.() || $("#diff");
25795
25818
  const empty = getEmptyPane?.() || $("#empty");
25796
- const expectedKeys = newFiles.map(fileKey);
25819
+ const expectedKeys = newFiles.map(fileKey2);
25797
25820
  const domIntact = isDiffShellDomIntact(target, expectedKeys);
25798
25821
  const sidebarNeedsRender = shouldRenderDiffSidebar(listSame, domIntact);
25799
25822
  if (!newFiles.length) {
@@ -25817,11 +25840,11 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25817
25840
  empty.classList.add("hidden");
25818
25841
  const newCardSigs = /* @__PURE__ */ new Map();
25819
25842
  for (const f2 of newFiles) {
25820
- newCardSigs.set(fileKey(f2), computeCardSignature(f2));
25843
+ newCardSigs.set(fileKey2(f2), computeCardSignature(f2));
25821
25844
  }
25822
25845
  const pathsUnknown = !changedPaths;
25823
25846
  const contentMayNeedReload = !listSame || pathsUnknown || (changedPaths ? newFiles.some((file) => {
25824
- const key = fileKey(file);
25847
+ const key = fileKey2(file);
25825
25848
  return prevCardSignatures.get(key) !== newCardSigs.get(key) || changedPathsCoverPath(changedPaths, file.path);
25826
25849
  }) : false);
25827
25850
  if (contentMayNeedReload) resetLoadScheduling();
@@ -25830,14 +25853,14 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25830
25853
  const cardsByKey = collectDiffCardsByKey(target);
25831
25854
  const measuredHeights = /* @__PURE__ */ new Map();
25832
25855
  for (const f2 of newFiles) {
25833
- const key = fileKey(f2);
25856
+ const key = fileKey2(f2);
25834
25857
  const card = cardsByKey.get(key);
25835
25858
  if (card && (card.classList.contains("loaded") || card.classList.contains("loading")))
25836
25859
  measuredHeights.set(key, card.offsetHeight);
25837
25860
  }
25838
25861
  let sidebarNeedsStatsUpdate = false;
25839
25862
  for (const f2 of newFiles) {
25840
- const key = fileKey(f2);
25863
+ const key = fileKey2(f2);
25841
25864
  const oldSig = prevCardSignatures.get(key);
25842
25865
  const newSig = newCardSigs.get(key) ?? computeCardSignature(f2);
25843
25866
  const sigChanged = oldSig !== newSig;
@@ -25893,7 +25916,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
25893
25916
  const oldByKey = collectDiffCardsByKey(target);
25894
25917
  const ordered = [];
25895
25918
  for (const f2 of newFiles) {
25896
- const key = fileKey(f2);
25919
+ const key = fileKey2(f2);
25897
25920
  const old = oldByKey.get(key);
25898
25921
  if (old) {
25899
25922
  oldByKey.delete(key);
@@ -26851,7 +26874,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
26851
26874
  const mount = getMount();
26852
26875
  return mount ? !mount.hidden : false;
26853
26876
  }
26854
- async function open() {
26877
+ async function open2() {
26855
26878
  const mount = getMount();
26856
26879
  if (!mount) return;
26857
26880
  bindOnce(mount);
@@ -26886,7 +26909,7 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
26886
26909
  if (!mount) return;
26887
26910
  await load(mount);
26888
26911
  }
26889
- return { open, close, isOpen, refresh };
26912
+ return { open: open2, close, isOpen, refresh };
26890
26913
  }
26891
26914
 
26892
26915
  // web-src/views/empty-diff-pane.ts
@@ -27372,12 +27395,12 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
27372
27395
  if (label) label.textContent = "";
27373
27396
  }
27374
27397
  function syncRefreshResult(result) {
27375
- const el = result ?? activeMount.refreshResult;
27376
- if (!el) return;
27377
- el.textContent = "";
27378
- el.hidden = true;
27379
- el.classList.toggle("changed", false);
27380
- el.classList.toggle("pending", false);
27398
+ const el2 = result ?? activeMount.refreshResult;
27399
+ if (!el2) return;
27400
+ el2.textContent = "";
27401
+ el2.hidden = true;
27402
+ el2.classList.toggle("changed", false);
27403
+ el2.classList.toggle("pending", false);
27381
27404
  }
27382
27405
  function syncFilterClearButton(button) {
27383
27406
  const clearButton = button ?? activeMount.filterClearButton;
@@ -27398,8 +27421,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
27398
27421
  }
27399
27422
  const gen = generation;
27400
27423
  const set2 = (sel, text3) => {
27401
- const el = info.querySelector(sel);
27402
- if (el) el.textContent = text3;
27424
+ const el2 = info.querySelector(sel);
27425
+ if (el2) el2.textContent = text3;
27403
27426
  };
27404
27427
  info.querySelector(".hci-head")?.removeAttribute("hidden");
27405
27428
  set2(".hci-sha", commit.sha);
@@ -27935,8 +27958,8 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
27935
27958
 
27936
27959
  // web-src/views/file-history-shell.ts
27937
27960
  function removeFileHistoryShell() {
27938
- document.querySelectorAll(".gdp-standalone-file-history").forEach((el) => {
27939
- (el.closest(".gdp-repo-blob-layout") || el).remove();
27961
+ document.querySelectorAll(".gdp-standalone-file-history").forEach((el2) => {
27962
+ (el2.closest(".gdp-repo-blob-layout") || el2).remove();
27940
27963
  });
27941
27964
  }
27942
27965
  function renderFileHistoryShell(deps, route, options = {}) {
@@ -28901,6 +28924,31 @@ ${entry.message}` : entry.detail ?? entry.message ?? "";
28901
28924
  }
28902
28925
  ]
28903
28926
  },
28927
+ {
28928
+ title: "Worktrees",
28929
+ blocks: [
28930
+ {
28931
+ kind: "paragraph",
28932
+ text: "The Worktrees item in the header menu lists every worktree of this repository — the main one and every linked worktree — in the same three-pane shape as History: pick a worktree on the left, its changed files in the middle, the diff on the right. Running one coding agent per worktree makes that spread invisible from inside a single checkout, and this screen is where it becomes visible again. The selection lives in the URL (?wt=…&file=…), so a reload comes back to the same diff."
28933
+ },
28934
+ {
28935
+ kind: "paragraph",
28936
+ text: `Every row in the left pane answers two things. How far the branch has drifted from the base branch (how many commits ahead and behind), and whether it still merges: code-viewer runs git merge-tree without touching any working tree, so a row says either that it merges cleanly, or how many files would conflict, or that the check could not run — the last one is kept separate from the first, because "not checked" is not "safe". The middle pane then splits that worktree's files into work that is not committed yet and commits made since the branch point, with added and deleted line counts; the diff itself is rendered by the same viewer the Diff screen uses, from git run inside that worktree.`
28937
+ },
28938
+ {
28939
+ kind: "paragraph",
28940
+ text: "The banner above the cards is the one to read first. It names every file that more than one worktree is currently changing, and the same files are marked inside each card. Two agents editing the same file is invisible until one of them merges; this is where it shows up before that happens. The base branch is whatever origin/HEAD points at, falling back to main and then master; each row names the one it used."
28941
+ },
28942
+ {
28943
+ kind: "paragraph",
28944
+ text: "Create makes a worktree under .worktrees/ in the repository root. You give it a folder name and the dialog shows the exact path it will create as you type; the branch defaults to that same name, so an existing branch is checked out and otherwise a new one starts from where you are. Because that folder sits inside the repository, git reports it as untracked until you add .worktrees/ to .gitignore — the dialog keeps that note behind a ? mark, and code-viewer never edits .gitignore for you. Remove deletes the worktree's folder from disk — the dialog says so, with the full path and a note that it cannot be undone — and keeps the branch and its committed work. With uncommitted changes the dialog also shows a warning and requires a checkbox before it deletes. An entry whose folder is already gone is cleaned from git's bookkeeping instead (git worktree prune), and the dialog says how many such entries will go. Because prune silently skips locked entries and still succeeds, code-viewer checks the entry is actually gone before reporting success and explains why if it is not. The worktree this server is serving cannot be removed from here. Delete sits on its own line, away from the everyday buttons, and stays muted until you reach for it."
28945
+ },
28946
+ {
28947
+ kind: "paragraph",
28948
+ text: 'Every row carries a "…" on the right, and every action for that worktree lives in it — no button appears just because you picked a row, and the row you act on is the row you opened the menu from, whether or not it is the one being shown. "Open in a new tab" starts a second code-viewer for that worktree, because a server stays on the working tree it started in; an already-running server is reused instead of started again. Those servers outlive this one, so "Stop its server" is in the same menu — the Server group in doctor still lists them all, and `kill <pid>` works too, with the pid in ~/.cache/code-viewer/servers/. A worktree that merges cleanly also offers to copy the `git switch` / `git merge` command; code-viewer copies it and never runs it. "Copy its address" is there because a new tab can be stopped by a browser extension before it loads (Chrome reports ERR_BLOCKED_BY_CLIENT) — the address still works in another browser or from a terminal. "Open folder" only appears for worktrees inside the repository, since that is the only place code-viewer will open on your behalf.'
28949
+ }
28950
+ ]
28951
+ },
28904
28952
  {
28905
28953
  title: "Environment doctor",
28906
28954
  blocks: [
@@ -29643,6 +29691,31 @@ code-viewer annotate add-db --db app.db --tab query \\
29643
29691
  }
29644
29692
  ]
29645
29693
  },
29694
+ {
29695
+ title: "作業ツリー",
29696
+ blocks: [
29697
+ {
29698
+ kind: "paragraph",
29699
+ text: "ヘッダメニューの「作業ツリー」は、このリポジトリの作業ツリーを本体ぶんも含めて並べます。画面の形は履歴と同じ 3 つの列で、左で作業ツリーを選び、中央にその変更ファイル、右に差分が出ます。コーディングエージェントを作業ツリーごとに走らせると、1 つのチェックアウトの中からは全体が見えなくなります。この画面はそれを見えるようにするためのものです。選んだものは URL に載る (?wt=…&file=…) ので、読み込み直しても同じ差分に戻ります。"
29700
+ },
29701
+ {
29702
+ kind: "paragraph",
29703
+ text: "左の 1 行が答えるのは 2 つです。基準ブランチからどれだけ離れているか(進んだぶん・遅れたぶんのコミット数)。そしてまだマージできるか — 作業ツリーを一切触らない git merge-tree で試し、「そのままマージできます」「マージすると何ファイルで衝突するか」「確かめられなかった」を出し分けます。最後のものは 1 番目と混ぜません。「確かめていない」は「安全」ではないからです。中央の列は、その作業ツリーが触っているファイルを、まだコミットしていないぶんと分岐した後のコミットに分けて、追加・削除の行数つきで出します。差分そのものは Diff ビューアと同じ描画で、その作業ツリーの中で走らせた git の結果です。"
29704
+ },
29705
+ {
29706
+ kind: "paragraph",
29707
+ text: "カードの上の帯を最初に読んでください。2 本以上の作業ツリーが今まさに触っているファイルを名指しで挙げ、同じファイルは各カードの中にも印が付きます。2 つのエージェントが同じファイルを書いていることは、どちらかをマージするまで表に出ません。ここはそれが起きる前に出る場所です。基準ブランチは origin/HEAD が指す先で、無ければ main、次に master を使います。どれを使ったかは各行に出ます。"
29708
+ },
29709
+ {
29710
+ kind: "paragraph",
29711
+ text: "「作る」はリポジトリ直下の .worktrees/ の下に作業ツリーを作ります。入力するのはフォルダ名で、打つそばから作られるパスがダイアログに出ます。ブランチは同じ名前が既定で、既にあるブランチならそれを開き、無ければいまの地点から新しく作ります。この置き場所はリポジトリの中なので、.worktrees/ を .gitignore に入れるまでは git から未追跡として見えます。その案内はダイアログの「?」に入れてあり、code-viewer が .gitignore を書き換えることはしません。「削除」はその作業ツリーのフォルダをディスクから消します。ダイアログにはフルパスと「元に戻せません」が出ます。ブランチとコミット済みの内容は残します。コミットしていない変更があるときは警告が出て、チェックを入れないと削除できません。フォルダが既に無い登録は git の管理情報の掃除 (git worktree prune) になり、同じ状態の登録が他にもあれば件数を出します。prune はロックされた登録を黙って飛ばして成功を返すので、消えたことを確かめてから成功と言います (残っていれば理由つきで断ります)。このサーバが映している作業ツリーはここからは消せません。削除だけは他の操作と段を分けて置いてあり、押すまでは沈んだ字で出ます。"
29712
+ },
29713
+ {
29714
+ kind: "paragraph",
29715
+ text: "各行の右端に「…」があり、その作業ツリーへの操作は全部その中にあります。行を選んだからといってボタンが現れることはなく、操作の相手は「…」を開いた行です(いま映している行である必要はありません)。「別タブで見る」はその作業ツリーで code-viewer をもう 1 本起こします。サーバは起動したときの作業ツリーから動けないためです。既に動いているサーバがあれば使い回します。起こしたサーバはこのサーバより長く生きるので、「サーバを止める」を同じメニューに置いてあります。doctor の Server グループには変わらず一覧が出ますし、`kill <pid>` でも止まります(pid は ~/.cache/code-viewer/servers/)。そのままマージできる作業ツリーには、取り込むコマンドのコピーも出ます。コピーするだけで、code-viewer が実行することはありません。「アドレスをコピー」があるのは、開いたタブがブラウザ拡張に止められることがあるためです(Chrome は ERR_BLOCKED_BY_CLIENT と出します)。アドレスさえ手元にあれば、別のブラウザやターミナルから開けます。「フォルダを開く」はリポジトリの中にある作業ツリーにだけ出ます。code-viewer が代わりに開くのはそこまでだからです。"
29716
+ }
29717
+ ]
29718
+ },
29646
29719
  {
29647
29720
  title: "環境ドクター",
29648
29721
  blocks: [
@@ -31810,13 +31883,13 @@ code-viewer annotate add-db --db app.db --tab query \\
31810
31883
  function clearTaskDropTargets() {
31811
31884
  root.querySelectorAll(
31812
31885
  ".journal-task-card.drop-target, .journal-task-column.drop-target"
31813
- ).forEach((el) => {
31814
- el.classList.remove("drop-target", "drop-after");
31886
+ ).forEach((el2) => {
31887
+ el2.classList.remove("drop-target", "drop-after");
31815
31888
  });
31816
31889
  }
31817
31890
  function clearTaskDragState() {
31818
- root.querySelectorAll(".journal-task-card.dragging").forEach((el) => {
31819
- el.classList.remove("dragging");
31891
+ root.querySelectorAll(".journal-task-card.dragging").forEach((el2) => {
31892
+ el2.classList.remove("dragging");
31820
31893
  });
31821
31894
  stopTaskDragAutoScroll();
31822
31895
  clearTaskDropTargets();
@@ -33110,7 +33183,7 @@ code-viewer annotate add-db --db app.db --tab query \\
33110
33183
  fullLink.textContent = text3.viewAll;
33111
33184
  settingsLink.textContent = text3.settings;
33112
33185
  }
33113
- function open() {
33186
+ function open2() {
33114
33187
  applyText();
33115
33188
  renderContent();
33116
33189
  popover.hidden = false;
@@ -33122,7 +33195,7 @@ code-viewer annotate add-db --db app.db --tab query \\
33122
33195
  }
33123
33196
  function toggle() {
33124
33197
  if (isOpen()) close();
33125
- else open();
33198
+ else open2();
33126
33199
  }
33127
33200
  trigger.addEventListener("click", toggle);
33128
33201
  closeBtn.addEventListener("click", close);
@@ -33152,7 +33225,7 @@ code-viewer annotate add-db --db app.db --tab query \\
33152
33225
  applyText();
33153
33226
  if (isOpen()) renderContent();
33154
33227
  }
33155
- return { open, close, toggle, isOpen, localize };
33228
+ return { open: open2, close, toggle, isOpen, localize };
33156
33229
  }
33157
33230
 
33158
33231
  // web-src/views/ref-picker.ts
@@ -33669,9 +33742,9 @@ code-viewer annotate add-db --db app.db --tab query \\
33669
33742
  syncSidebarHeaderHeight();
33670
33743
  }
33671
33744
  let SIDEBAR_FILES = [];
33672
- function setFolderIcon(el, collapsed) {
33745
+ function setFolderIcon(el2, collapsed) {
33673
33746
  const path = collapsed ? FOLDER_ICON_PATHS.closed : FOLDER_ICON_PATHS.open;
33674
- el.innerHTML = '<svg class="octicon octicon-file-directory-' + (collapsed ? "fill" : "open-fill") + '" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true"><path fill="currentColor" d="' + path + '"></path></svg>';
33747
+ el2.innerHTML = '<svg class="octicon octicon-file-directory-' + (collapsed ? "fill" : "open-fill") + '" viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true"><path fill="currentColor" d="' + path + '"></path></svg>';
33675
33748
  }
33676
33749
  function setSidebarTreeActionIcons() {
33677
33750
  const sidebarToggle = ensureSidebarToggleButton();
@@ -34281,13 +34354,13 @@ code-viewer annotate add-db --db app.db --tab query \\
34281
34354
  input2.toggleAttribute("aria-invalid", invalid);
34282
34355
  input2.title = invalid ? filter.error || "invalid regular expression" : "";
34283
34356
  const filterActive = filter.kind !== "empty" && !invalid;
34284
- const matches = invalid ? () => true : filter.match;
34357
+ const matches2 = invalid ? () => true : filter.match;
34285
34358
  const walk = (node, depth) => {
34286
34359
  let subtreeVisible = false;
34287
34360
  const rows = [];
34288
34361
  for (const item of treeNodeItems(node)) {
34289
34362
  if (item.kind === "dir") {
34290
- const dirMatches = filterActive && matches(item.dir.path);
34363
+ const dirMatches = filterActive && matches2(item.dir.path);
34291
34364
  const eff = dirEffectiveCollapsed(item.dir);
34292
34365
  const expanded = !item.dir.children_omitted && !eff.lazyNotLoaded && (filterActive ? !eff.userCollapsed : !eff.effectiveCollapsed);
34293
34366
  const child = walk(item.dir, depth + 1);
@@ -34305,7 +34378,7 @@ code-viewer annotate add-db --db app.db --tab query \\
34305
34378
  subtreeVisible = subtreeVisible || visible;
34306
34379
  } else {
34307
34380
  const testHidden = STATE.hideTests && !isRepositorySidebarMode() && isTestPath(item.file.path || "");
34308
- const visible = !testHidden && matches(item.file.path || "");
34381
+ const visible = !testHidden && matches2(item.file.path || "");
34309
34382
  if (visible) {
34310
34383
  rows.push({
34311
34384
  kind: "file",
@@ -34703,19 +34776,19 @@ code-viewer annotate add-db --db app.db --tab query \\
34703
34776
  const invalid = filter.kind === "invalid";
34704
34777
  input2.toggleAttribute("aria-invalid", invalid);
34705
34778
  input2.title = invalid ? filter.error || "invalid regular expression" : "";
34706
- const matches = invalid ? () => true : filter.match;
34779
+ const matches2 = invalid ? () => true : filter.match;
34707
34780
  const filterActive = filter.kind !== "empty" && !invalid;
34708
34781
  $$("#filelist li[data-path]").forEach((li) => {
34709
- const match2 = matches(li.dataset.path || "");
34782
+ const match2 = matches2(li.dataset.path || "");
34710
34783
  li.classList.toggle("hidden", !match2);
34711
34784
  });
34712
34785
  if (!isRepositorySidebarMode()) {
34713
34786
  document.querySelectorAll(".gdp-file-shell").forEach((card) => {
34714
- const match2 = matches(card.dataset.path || "");
34787
+ const match2 = matches2(card.dataset.path || "");
34715
34788
  card.classList.toggle("hidden-by-filter", !match2);
34716
34789
  });
34717
34790
  }
34718
- updateTreeDirVisibility(matches, filterActive);
34791
+ updateTreeDirVisibility(matches2, filterActive);
34719
34792
  if (!isRepositorySidebarMode() && typeof applyViewedState === "function")
34720
34793
  applyViewedState();
34721
34794
  }
@@ -34769,6 +34842,7 @@ code-viewer annotate add-db --db app.db --tab query \\
34769
34842
  const input2 = document.querySelector("#sb-filter");
34770
34843
  if (!input2?.value) return;
34771
34844
  input2.value = "";
34845
+ input2.dispatchEvent(new Event("input", { bubbles: true }));
34772
34846
  syncSidebarFilterClearButton();
34773
34847
  flushSidebarFilter();
34774
34848
  applyFilter();
@@ -37242,11 +37316,11 @@ code-viewer annotate add-db --db app.db --tab query \\
37242
37316
  const grouped = /* @__PURE__ */ new Map();
37243
37317
  state.items.forEach((item, index) => {
37244
37318
  if (item.kind !== "grep") return;
37245
- const matches = grouped.get(item.path) ?? [];
37246
- matches.push({ item, index });
37247
- grouped.set(item.path, matches);
37319
+ const matches2 = grouped.get(item.path) ?? [];
37320
+ matches2.push({ item, index });
37321
+ grouped.set(item.path, matches2);
37248
37322
  });
37249
- for (const [path, matches] of grouped) {
37323
+ for (const [path, matches2] of grouped) {
37250
37324
  const group = document.createElement("section");
37251
37325
  group.className = "gdp-palette-file-group";
37252
37326
  group.setAttribute("role", "group");
@@ -37259,11 +37333,11 @@ code-viewer annotate add-db --db app.db --tab query \\
37259
37333
  name.title = path;
37260
37334
  const count = document.createElement("span");
37261
37335
  count.className = "gdp-palette-file-heading-count";
37262
- count.textContent = String(matches.length);
37336
+ count.textContent = String(matches2.length);
37263
37337
  heading2.append(name, count);
37264
37338
  const rows = document.createElement("div");
37265
37339
  rows.className = "gdp-palette-file-matches";
37266
- for (const match2 of matches) {
37340
+ for (const match2 of matches2) {
37267
37341
  rows.appendChild(
37268
37342
  createPaletteRow(state, match2.item, match2.index, true)
37269
37343
  );
@@ -38028,11 +38102,11 @@ code-viewer annotate add-db --db app.db --tab query \\
38028
38102
  return STATE.route.screen === "file" ? { path: STATE.route.path, ref: STATE.route.ref } : null;
38029
38103
  }
38030
38104
  function removeStandaloneSource() {
38031
- document.querySelectorAll(".gdp-standalone-source").forEach((el) => {
38032
- el.remove();
38105
+ document.querySelectorAll(".gdp-standalone-source").forEach((el2) => {
38106
+ el2.remove();
38033
38107
  });
38034
- document.querySelectorAll(".gdp-repo-blob-layout").forEach((el) => {
38035
- el.remove();
38108
+ document.querySelectorAll(".gdp-repo-blob-layout").forEach((el2) => {
38109
+ el2.remove();
38036
38110
  });
38037
38111
  }
38038
38112
  function renderSourceLoading(card, target, onCancel) {
@@ -38598,17 +38672,17 @@ code-viewer annotate add-db --db app.db --tab query \\
38598
38672
  return ranges;
38599
38673
  }
38600
38674
  function collectVirtualSourceSearchMatches(lines, query, max = 5e3) {
38601
- const matches = [];
38602
- for (let index = 0; index < lines.length && matches.length < max; index++) {
38675
+ const matches2 = [];
38676
+ for (let index = 0; index < lines.length && matches2.length < max; index++) {
38603
38677
  for (const range of virtualSourceSearchRanges(
38604
38678
  lines[index] || "",
38605
38679
  query
38606
38680
  )) {
38607
- matches.push({ line: index + 1, start: range.start, end: range.end });
38608
- if (matches.length >= max) break;
38681
+ matches2.push({ line: index + 1, start: range.start, end: range.end });
38682
+ if (matches2.length >= max) break;
38609
38683
  }
38610
38684
  }
38611
- return matches;
38685
+ return matches2;
38612
38686
  }
38613
38687
  function appendVirtualSourceLineCode(code2, line, query, activeRange, lineNumber) {
38614
38688
  const ranges = virtualSourceSearchRanges(line, query);
@@ -38652,7 +38726,7 @@ code-viewer annotate add-db --db app.db --tab query \\
38652
38726
  bar.append(input2, count, previous, next, close);
38653
38727
  wrap.querySelector(".gdp-source-virtual-info")?.appendChild(bar);
38654
38728
  bar.hidden = true;
38655
- let matches = [];
38729
+ let matches2 = [];
38656
38730
  let active = -1;
38657
38731
  let debounce = 0;
38658
38732
  let searchVersion = 0;
@@ -38665,7 +38739,7 @@ code-viewer annotate add-db --db app.db --tab query \\
38665
38739
  const query = input2.value;
38666
38740
  const version = ++searchVersion;
38667
38741
  if (!query) {
38668
- matches = [];
38742
+ matches2 = [];
38669
38743
  active = -1;
38670
38744
  count.textContent = "";
38671
38745
  renderFn();
@@ -38674,20 +38748,20 @@ code-viewer annotate add-db --db app.db --tab query \\
38674
38748
  count.textContent = "Searching...";
38675
38749
  findMatches(query).then((nextMatches) => {
38676
38750
  if (version !== searchVersion) return;
38677
- matches = nextMatches;
38678
- active = matches.length ? Math.max(0, Math.min(active, matches.length - 1)) : -1;
38679
- count.textContent = matches.length ? `${active + 1} / ${matches.length}` : "0 / 0";
38751
+ matches2 = nextMatches;
38752
+ active = matches2.length ? Math.max(0, Math.min(active, matches2.length - 1)) : -1;
38753
+ count.textContent = matches2.length ? `${active + 1} / ${matches2.length}` : "0 / 0";
38680
38754
  if (active >= 0) {
38681
38755
  const rowHeight = sourceLineScrollAmount() || VIRTUAL_SOURCE_ROW_HEIGHT;
38682
38756
  scroller.scrollTop = Math.max(
38683
38757
  0,
38684
- (matches[active].line - 1) * rowHeight - rowHeight * 3
38758
+ (matches2[active].line - 1) * rowHeight - rowHeight * 3
38685
38759
  );
38686
38760
  }
38687
38761
  renderFn();
38688
38762
  }).catch(() => {
38689
38763
  if (version !== searchVersion) return;
38690
- matches = [];
38764
+ matches2 = [];
38691
38765
  active = -1;
38692
38766
  count.textContent = "Search failed";
38693
38767
  renderFn();
@@ -38698,13 +38772,13 @@ code-viewer annotate add-db --db app.db --tab query \\
38698
38772
  debounce = window.setTimeout(sync, 120);
38699
38773
  };
38700
38774
  const move = (direction) => {
38701
- if (!matches.length) return;
38702
- active = (active + direction + matches.length) % matches.length;
38703
- count.textContent = `${active + 1} / ${matches.length}`;
38775
+ if (!matches2.length) return;
38776
+ active = (active + direction + matches2.length) % matches2.length;
38777
+ count.textContent = `${active + 1} / ${matches2.length}`;
38704
38778
  const rowHeight = sourceLineScrollAmount() || VIRTUAL_SOURCE_ROW_HEIGHT;
38705
38779
  scroller.scrollTop = Math.max(
38706
38780
  0,
38707
- (matches[active].line - 1) * rowHeight - rowHeight * 3
38781
+ (matches2[active].line - 1) * rowHeight - rowHeight * 3
38708
38782
  );
38709
38783
  renderFn();
38710
38784
  };
@@ -38733,7 +38807,7 @@ code-viewer annotate add-db --db app.db --tab query \\
38733
38807
  sync();
38734
38808
  },
38735
38809
  query: () => bar.hidden ? "" : input2.value,
38736
- activeRange: () => active >= 0 ? matches[active] || null : null
38810
+ activeRange: () => active >= 0 ? matches2[active] || null : null
38737
38811
  };
38738
38812
  }
38739
38813
  function openVirtualSourceSearchFromKeyboard(targetEl) {
@@ -39100,10 +39174,10 @@ code-viewer annotate add-db --db app.db --tab query \\
39100
39174
  scroller.__gdpRenderVirtualSource = render;
39101
39175
  scroller.addEventListener("scroll", schedule, { passive: true });
39102
39176
  const findPagedMatches = async (query, matchSignal) => {
39103
- const matches = [];
39177
+ const matches2 = [];
39104
39178
  let startLine = 1;
39105
39179
  let done = false;
39106
- while (!done && matches.length < 5e3) {
39180
+ while (!done && matches2.length < 5e3) {
39107
39181
  const endLine = startLine + VIRTUAL_SOURCE_PAGE_SIZE - 1;
39108
39182
  const data = await trackLoad(
39109
39183
  fetch(buildFileRangeUrl(target, startLine, endLine), {
@@ -39118,12 +39192,12 @@ code-viewer annotate add-db --db app.db --tab query \\
39118
39192
  const lineNumber = data.start + index;
39119
39193
  lines.set(lineNumber, lineValue);
39120
39194
  for (const range of virtualSourceSearchRanges(lineValue, query)) {
39121
- matches.push({
39195
+ matches2.push({
39122
39196
  line: lineNumber,
39123
39197
  start: range.start,
39124
39198
  end: range.end
39125
39199
  });
39126
- if (matches.length >= 5e3) break;
39200
+ if (matches2.length >= 5e3) break;
39127
39201
  }
39128
39202
  });
39129
39203
  totalRows = data.complete ? Math.max(1, data.total) : Math.max(totalRows, data.total, endLine + VIRTUAL_SOURCE_PAGE_SIZE);
@@ -39135,7 +39209,7 @@ code-viewer annotate add-db --db app.db --tab query \\
39135
39209
  renderedStart = -1;
39136
39210
  renderedEnd = -1;
39137
39211
  schedule();
39138
- return matches;
39212
+ return matches2;
39139
39213
  };
39140
39214
  search = createVirtualSourceSearch(
39141
39215
  wrap,
@@ -39313,8 +39387,8 @@ code-viewer annotate add-db --db app.db --tab query \\
39313
39387
  const repoTarget = repoFileTargetFromRoute();
39314
39388
  setPageMode();
39315
39389
  removeStandaloneSource();
39316
- document.querySelectorAll(".gdp-repo-blob-layout").forEach((el) => {
39317
- el.remove();
39390
+ document.querySelectorAll(".gdp-repo-blob-layout").forEach((el2) => {
39391
+ el2.remove();
39318
39392
  });
39319
39393
  const card = document.createElement("article");
39320
39394
  card.className = "gdp-file-shell loaded gdp-standalone-source gdp-source-mode";
@@ -39785,13 +39859,13 @@ code-viewer annotate add-db --db app.db --tab query \\
39785
39859
  }
39786
39860
 
39787
39861
  // web-src/core/scroll-chaining.ts
39788
- function hasScrollRoom(el, event) {
39789
- const up = event.deltaY < 0 && el.scrollTop > 1;
39790
- const down = event.deltaY > 0 && el.scrollHeight - el.clientHeight - el.scrollTop > 1;
39791
- const left = event.deltaX < 0 && el.scrollLeft > 1;
39792
- const right = event.deltaX > 0 && el.scrollWidth - el.clientWidth - el.scrollLeft > 1;
39862
+ function hasScrollRoom(el2, event) {
39863
+ const up = event.deltaY < 0 && el2.scrollTop > 1;
39864
+ const down = event.deltaY > 0 && el2.scrollHeight - el2.clientHeight - el2.scrollTop > 1;
39865
+ const left = event.deltaX < 0 && el2.scrollLeft > 1;
39866
+ const right = event.deltaX > 0 && el2.scrollWidth - el2.clientWidth - el2.scrollLeft > 1;
39793
39867
  if (!up && !down && !left && !right) return false;
39794
- const style = getComputedStyle(el);
39868
+ const style = getComputedStyle(el2);
39795
39869
  const scrollsY = style.overflowY === "auto" || style.overflowY === "scroll";
39796
39870
  const scrollsX = style.overflowX === "auto" || style.overflowX === "scroll";
39797
39871
  return (up || down) && scrollsY || (left || right) && scrollsX;
@@ -39999,8 +40073,8 @@ code-viewer annotate add-db --db app.db --tab query \\
39999
40073
  return parts.join(BRANCH_KEY_SEP);
40000
40074
  }
40001
40075
  function createSessionBoard(deps) {
40002
- const el = document.createElement("div");
40003
- el.className = "terminal-board";
40076
+ const el2 = document.createElement("div");
40077
+ el2.className = "terminal-board";
40004
40078
  const scopeBar = document.createElement("div");
40005
40079
  scopeBar.className = "terminal-scope";
40006
40080
  const scopeSelect = document.createElement("select");
@@ -40043,7 +40117,7 @@ code-viewer annotate add-db --db app.db --tab query \\
40043
40117
  tree.role = "tree";
40044
40118
  const treeEmpty = document.createElement("p");
40045
40119
  treeEmpty.className = "terminal-empty";
40046
- el.append(scopeBar, observationErrors, attentionSection, filters, tree);
40120
+ el2.append(scopeBar, observationErrors, attentionSection, filters, tree);
40047
40121
  let data = {
40048
40122
  panes: null,
40049
40123
  shells: [],
@@ -40116,12 +40190,12 @@ code-viewer annotate add-db --db app.db --tab query \\
40116
40190
  }
40117
40191
  const actions = document.createElement("div");
40118
40192
  actions.className = "terminal-card-actions";
40119
- const open = document.createElement("button");
40120
- open.type = "button";
40121
- open.className = `terminal-card-open terminal-card-open-${row.state}`;
40122
- open.textContent = text3.openTarget;
40123
- open.addEventListener("click", () => activate(row));
40124
- actions.appendChild(open);
40193
+ const open2 = document.createElement("button");
40194
+ open2.type = "button";
40195
+ open2.className = `terminal-card-open terminal-card-open-${row.state}`;
40196
+ open2.textContent = text3.openTarget;
40197
+ open2.addEventListener("click", () => activate(row));
40198
+ actions.appendChild(open2);
40125
40199
  if (row.state === "done") {
40126
40200
  const read = document.createElement("button");
40127
40201
  read.type = "button";
@@ -40415,7 +40489,7 @@ ${error2.stack}` : ""}`;
40415
40489
  }
40416
40490
  render();
40417
40491
  return {
40418
- el,
40492
+ el: el2,
40419
40493
  setData(next) {
40420
40494
  data = next;
40421
40495
  render();
@@ -40471,17 +40545,17 @@ ${error2.stack}` : ""}`;
40471
40545
  previouslyFocused?.focus?.();
40472
40546
  };
40473
40547
  const button = (label, title2, onClick) => {
40474
- const el = document.createElement("button");
40475
- el.type = "button";
40476
- el.className = "terminal-font-btn";
40477
- el.textContent = label;
40478
- el.title = title2;
40479
- el.setAttribute("aria-label", title2);
40480
- el.addEventListener("click", (event) => {
40548
+ const el2 = document.createElement("button");
40549
+ el2.type = "button";
40550
+ el2.className = "terminal-font-btn";
40551
+ el2.textContent = label;
40552
+ el2.title = title2;
40553
+ el2.setAttribute("aria-label", title2);
40554
+ el2.addEventListener("click", (event) => {
40481
40555
  event.stopPropagation();
40482
40556
  onClick();
40483
40557
  });
40484
- return el;
40558
+ return el2;
40485
40559
  };
40486
40560
  zoomReset = button("100%", text3.zoomReset, () => viewport.reset());
40487
40561
  actions.append(
@@ -40536,14 +40610,14 @@ ${error2.stack}` : ""}`;
40536
40610
  var INLINE_IMAGE_COLS = 30;
40537
40611
  var INLINE_IMAGE_ROWS = 8;
40538
40612
  function createTerminalScreen(deps) {
40539
- const el = document.createElement("div");
40540
- el.className = "terminal-pane-body";
40613
+ const el2 = document.createElement("div");
40614
+ el2.className = "terminal-pane-body";
40541
40615
  const attachments = document.createElement("div");
40542
40616
  attachments.className = "terminal-attachments";
40543
40617
  attachments.hidden = true;
40544
40618
  const screenEl = document.createElement("div");
40545
40619
  screenEl.className = "terminal-screen";
40546
- el.append(attachments, screenEl);
40620
+ el2.append(attachments, screenEl);
40547
40621
  let term = null;
40548
40622
  let fitAddon = null;
40549
40623
  let source = null;
@@ -40664,13 +40738,13 @@ ${formatErrorDetail(error2)}`
40664
40738
  function addAttachment(src, name, path) {
40665
40739
  const item = document.createElement("div");
40666
40740
  item.className = "terminal-attachment";
40667
- const open = document.createElement("button");
40668
- open.type = "button";
40669
- open.className = "terminal-attachment-open";
40741
+ const open2 = document.createElement("button");
40742
+ open2.type = "button";
40743
+ open2.className = "terminal-attachment-open";
40670
40744
  const openLabel = deps.getText().openImage;
40671
- open.title = path;
40672
- open.setAttribute("aria-label", `${openLabel}: ${name}`);
40673
- open.addEventListener("click", () => {
40745
+ open2.title = path;
40746
+ open2.setAttribute("aria-label", `${openLabel}: ${name}`);
40747
+ open2.addEventListener("click", () => {
40674
40748
  openImageLightbox({ url: src, name, path }, deps.getText());
40675
40749
  });
40676
40750
  const image2 = document.createElement("img");
@@ -40688,7 +40762,7 @@ ${formatErrorDetail(error2)}`
40688
40762
  );
40689
40763
  }
40690
40764
  });
40691
- open.appendChild(image2);
40765
+ open2.appendChild(image2);
40692
40766
  const label = document.createElement("span");
40693
40767
  label.className = "terminal-attachment-name";
40694
40768
  label.textContent = name;
@@ -40703,7 +40777,7 @@ ${formatErrorDetail(error2)}`
40703
40777
  item.remove();
40704
40778
  attachments.hidden = attachments.childElementCount === 0;
40705
40779
  });
40706
- item.append(open, label, remove);
40780
+ item.append(open2, label, remove);
40707
40781
  attachments.appendChild(item);
40708
40782
  attachments.hidden = false;
40709
40783
  }
@@ -40928,7 +41002,7 @@ ${formatErrorDetail(error2)}`
40928
41002
  }
40929
41003
  return null;
40930
41004
  }
40931
- el.addEventListener(
41005
+ el2.addEventListener(
40932
41006
  "paste",
40933
41007
  (event) => {
40934
41008
  const file = firstImage(event.clipboardData);
@@ -41080,7 +41154,7 @@ ${formatErrorDetail(error2)}`
41080
41154
  deps.onStatus(null);
41081
41155
  }
41082
41156
  return {
41083
- el,
41157
+ el: el2,
41084
41158
  applyFontSize() {
41085
41159
  if (!term) return;
41086
41160
  term.options.fontSize = deps.getFontSize();
@@ -41562,7 +41636,7 @@ ${formatErrorDetail(error2)}`);
41562
41636
  const host = getMount();
41563
41637
  return host ? !host.hidden : false;
41564
41638
  }
41565
- async function open(id) {
41639
+ async function open2(id) {
41566
41640
  const host = getMount();
41567
41641
  if (!host || disposed) return;
41568
41642
  const myGen = ++generation;
@@ -41621,7 +41695,7 @@ ${formatErrorDetail(error2)}`);
41621
41695
  renderLists();
41622
41696
  }
41623
41697
  return {
41624
- open,
41698
+ open: open2,
41625
41699
  close,
41626
41700
  isOpen,
41627
41701
  getActiveTarget: () => attached?.id ?? lastTargetId,
@@ -41772,8 +41846,8 @@ ${formatErrorDetail(error2)}`);
41772
41846
  }
41773
41847
  function createScratchpadPane(text3, outputTitle, placeholder, options) {
41774
41848
  let currentText = text3;
41775
- const el = document.createElement("div");
41776
- el.className = `tools-pane ${options.toolClassName}`;
41849
+ const el2 = document.createElement("div");
41850
+ el2.className = `tools-pane ${options.toolClassName}`;
41777
41851
  const inputSide = document.createElement("section");
41778
41852
  inputSide.className = "tools-pane-side tools-pane-input";
41779
41853
  const { head: inputHead, titleEl: inputTitle } = createHead(text3.pane.input);
@@ -41808,7 +41882,7 @@ ${formatErrorDetail(error2)}`);
41808
41882
  const output = document.createElement("div");
41809
41883
  output.className = "tools-pane-body";
41810
41884
  outputSide.append(outputHead, output);
41811
- el.append(inputSide, resizer, outputSide);
41885
+ el2.append(inputSide, resizer, outputSide);
41812
41886
  let statusTimer = null;
41813
41887
  let pinnedStatus = null;
41814
41888
  let normalStatus = { message: "", tone: "info" };
@@ -41888,21 +41962,21 @@ ${formatErrorDetail(error2)}`);
41888
41962
  });
41889
41963
  const MIN_SIDE_WIDTH = 220;
41890
41964
  function applyInputWidth(width) {
41891
- const total = el.getBoundingClientRect().width;
41965
+ const total = el2.getBoundingClientRect().width;
41892
41966
  const max = Math.max(MIN_SIDE_WIDTH, total - MIN_SIDE_WIDTH);
41893
41967
  const clamped = Math.max(MIN_SIDE_WIDTH, Math.min(max, width));
41894
- el.style.setProperty("--tools-input-width", `${Math.round(clamped)}px`);
41968
+ el2.style.setProperty("--tools-input-width", `${Math.round(clamped)}px`);
41895
41969
  }
41896
41970
  const detachResizer = attachDragResizer({
41897
41971
  handle: resizer,
41898
41972
  getSize: () => inputSide.getBoundingClientRect().width,
41899
41973
  applySize: applyInputWidth,
41900
41974
  direction: 1,
41901
- activeClassTarget: el,
41975
+ activeClassTarget: el2,
41902
41976
  activeClassName: "tools-pane-resizing"
41903
41977
  });
41904
41978
  return {
41905
- el,
41979
+ el: el2,
41906
41980
  input: input2,
41907
41981
  output,
41908
41982
  setStatus,
@@ -42426,7 +42500,7 @@ ${formatErrorDetail(error2)}`);
42426
42500
  const host = getMount();
42427
42501
  return host ? !host.hidden : false;
42428
42502
  }
42429
- async function open(tool) {
42503
+ async function open2(tool) {
42430
42504
  const host = getMount();
42431
42505
  if (!host) return;
42432
42506
  const myGen = ++generation;
@@ -42483,7 +42557,7 @@ ${formatErrorDetail(error2)}`);
42483
42557
  };
42484
42558
  window.addEventListener("beforeunload", onBeforeUnload);
42485
42559
  return {
42486
- open,
42560
+ open: open2,
42487
42561
  close,
42488
42562
  isOpen,
42489
42563
  getActiveTool: () => activeTool,
@@ -43137,6 +43211,1704 @@ ${formatErrorDetail(error2)}`);
43137
43211
  return { mount, sync, localize };
43138
43212
  }
43139
43213
 
43214
+ // web-src/views/worktree-i18n.ts
43215
+ var EN_STATUS_TITLES = {
43216
+ M: "modified",
43217
+ A: "added",
43218
+ D: "deleted",
43219
+ R: "renamed",
43220
+ C: "copied",
43221
+ U: "untracked"
43222
+ };
43223
+ var JA_STATUS_TITLES = {
43224
+ M: "変更",
43225
+ A: "追加",
43226
+ D: "削除",
43227
+ R: "リネーム",
43228
+ C: "コピー",
43229
+ U: "未追跡"
43230
+ };
43231
+ var TEXT3 = {
43232
+ en: {
43233
+ title: "Worktrees",
43234
+ ariaLabel: "Git worktrees",
43235
+ loading: "Loading worktrees…",
43236
+ loadFailed: "Failed to load worktrees.",
43237
+ empty: "No worktrees.",
43238
+ refresh: "Reload",
43239
+ refreshTitle: "Reload the worktree list",
43240
+ count: (n2) => n2 === 1 ? "1 worktree" : `${n2} worktrees`,
43241
+ baseUnknown: "no base branch found",
43242
+ gitignoreHint: "Git sees that directory as untracked. Add .worktrees/ to .gitignore to keep it out of git status.",
43243
+ badges: {
43244
+ current: "this folder",
43245
+ currentTitle: "This code-viewer is serving this folder",
43246
+ detached: "no branch",
43247
+ detachedTitle: "Not attached to any branch (detached HEAD)",
43248
+ bare: "bare",
43249
+ bareTitle: "A storage-only repository with no working files",
43250
+ locked: "locked",
43251
+ prunable: "stale entry",
43252
+ prunableTitle: "Only the git entry remains (e.g. the folder is gone)",
43253
+ missing: "folder is gone",
43254
+ running: "running",
43255
+ runningTitle: "A code-viewer for this folder is running on another port"
43256
+ },
43257
+ diverge: {
43258
+ ahead: (n2, base2) => n2 === 1 ? `1 commit ahead of ${base2}` : `${n2} commits ahead of ${base2}`,
43259
+ behind: (n2, base2) => n2 === 1 ? `1 commit behind ${base2}` : `${n2} commits behind ${base2}`,
43260
+ even: (base2) => `same point as ${base2}`,
43261
+ notComparable: "not compared"
43262
+ },
43263
+ merge: {
43264
+ clean: "merges cleanly",
43265
+ conflict: (n2) => n2 === 1 ? "1 file would conflict on merge" : `${n2} files would conflict on merge`,
43266
+ unknown: "could not check the merge",
43267
+ conflictListLabel: "Conflicting files"
43268
+ },
43269
+ files: {
43270
+ heading: (n2) => n2 === 1 ? "1 changed file" : `${n2} changed files`,
43271
+ none: "No changes.",
43272
+ uncommitted: "Not committed yet",
43273
+ committed: "Committed, not merged",
43274
+ truncated: (shown, total) => `showing ${shown} of ${total}`,
43275
+ // 行の中に置くので短くする。誰と重なっているかは title に入る。
43276
+ overlapMark: "shared",
43277
+ overlapTitle: (others) => `Also changed in: ${others.join(", ")}`,
43278
+ statusTitles: EN_STATUS_TITLES
43279
+ },
43280
+ overlaps: {
43281
+ heading: (n2) => n2 === 1 ? "1 file is touched by more than one worktree" : `${n2} files are touched by more than one worktree`,
43282
+ intro: "Merging one of them will make the others conflict on these files.",
43283
+ entry: (path, worktrees) => `${path} — ${worktrees.join(", ")}`
43284
+ },
43285
+ panes: {
43286
+ worktrees: "Worktrees",
43287
+ files: "Files",
43288
+ diff: "Diff",
43289
+ filterWorktrees: "Filter worktrees…",
43290
+ filterFiles: "Filter files…",
43291
+ noWorktreeMatch: "No worktree matches.",
43292
+ noFileMatch: "No file matches.",
43293
+ selectWorktree: "Pick a worktree to see what it is changing.",
43294
+ selectFile: "Pick a file to see its diff.",
43295
+ diffLoading: "Loading the diff…",
43296
+ diffEmpty: "No textual diff (binary, or the file is unchanged).",
43297
+ diffFailed: "Failed to load the diff.",
43298
+ diffTruncated: (shown, total) => `showing ${shown} of ${total} hunks — open the worktree in a new tab for the whole file`
43299
+ },
43300
+ noCommit: "no commit",
43301
+ lastTouched: (when) => `updated ${when}`,
43302
+ actions: {
43303
+ menuTitle: "Actions for this worktree",
43304
+ menuFor: (name) => `Actions for ${name}`,
43305
+ openFolder: "Open folder",
43306
+ openFolderTitle: "Open this folder in the OS file manager",
43307
+ openFolderFailed: "Could not open that folder.",
43308
+ copyPath: "Copy path",
43309
+ copyPathTitle: "Copy the path to this folder",
43310
+ copyFailed: "Could not copy to the clipboard.",
43311
+ stopServer: "Stop its server",
43312
+ stopServerTitle: "Stop the code-viewer running for this folder",
43313
+ stopFailed: "Failed to stop the server.",
43314
+ copyServerUrl: "Copy its address",
43315
+ copyServerUrlTitle: (url) => `Copy ${url}`,
43316
+ copyMerge: "Copy merge command",
43317
+ copyMergeTitle: (base2, branch) => `Copy the command that merges ${branch} into ${base2}`
43318
+ },
43319
+ emptyDiff: {
43320
+ title: "No changes yet.",
43321
+ body: (path) => `Edit files in ${path} and the diffs will show up here.`
43322
+ },
43323
+ intro: {
43324
+ cardTitle: "What is a worktree?",
43325
+ cardWhat: "A worktree (git worktree) is a second checkout of this repository, in a separate folder on a separate branch.",
43326
+ cardWhy: "Keep main open here while a bugfix branch stays open over there — no branch switching, no stashing.",
43327
+ cardHow: 'When you click "Create": a new folder appears at .worktrees/<name>, with the branch checked out in it. Edit files there as usual. The changes show up on this screen as diffs.',
43328
+ cardButton: "Create a worktree",
43329
+ listNote: "This is the only folder right now. New worktrees will appear here.",
43330
+ overlapLegend: "⇄ = another worktree is changing this file too"
43331
+ },
43332
+ open: "Open in a new tab",
43333
+ openTitle: "Start a code-viewer for this folder and open it in a new tab",
43334
+ opening: "Starting…",
43335
+ openFailed: "Failed to open this worktree.",
43336
+ add: "Create",
43337
+ addTitle: "Create a new worktree",
43338
+ addFailed: "Failed to create the worktree.",
43339
+ addDialog: {
43340
+ title: "Create a worktree",
43341
+ intro: "Work on two things side by side, in separate folders, without switching branches.",
43342
+ nameLabel: "Folder name",
43343
+ namePlaceholder: "feature-x",
43344
+ branchLabel: "Branch",
43345
+ branchPlaceholder: "same as the folder name",
43346
+ branchHint: "An existing branch name opens that branch. Otherwise a new one starts from where you are now.",
43347
+ targetLabel: "Creates",
43348
+ targetPending: (parent) => `${parent}/…`,
43349
+ gitignoreLabel: "About this folder and git status",
43350
+ submit: "Create"
43351
+ },
43352
+ remove: "Delete this worktree",
43353
+ removeTitle: "Delete this worktree and its folder",
43354
+ removeDialog: {
43355
+ title: "Delete worktree",
43356
+ body: (name) => `Delete the worktree "${name}"?`,
43357
+ diskNote: (path) => `The folder ${path} and everything in it will be deleted from disk. This cannot be undone.`,
43358
+ branchNote: (branch) => `The branch ${branch} and its committed work are kept.`,
43359
+ dirtyNote: (count) => count === 1 ? "1 file has uncommitted changes." : `${count} files have uncommitted changes.`,
43360
+ dirtyLose: "Deleting the worktree will lose them.",
43361
+ force: "Delete even with uncommitted changes",
43362
+ forceRequired: "To delete it anyway, check the box first.",
43363
+ missingBody: (name) => `Remove the entry for "${name}"?`,
43364
+ missingNote: "Its folder is already gone from disk; only the git entry is removed.",
43365
+ lockedNote: "This entry is locked, so git will leave it in place. Unlock it first.",
43366
+ missingOthers: (n2) => n2 === 1 ? "1 other entry whose folder is gone will be cleaned up at the same time." : `${n2} other entries whose folders are gone will be cleaned up at the same time.`,
43367
+ submit: "Delete"
43368
+ },
43369
+ removeFailed: "Failed to delete the worktree.",
43370
+ cancel: "Cancel",
43371
+ nameErrors: {
43372
+ empty: "Enter a name.",
43373
+ control: "Control characters cannot be used.",
43374
+ separator: "Path separators cannot be used.",
43375
+ relative: "This name is not allowed.",
43376
+ "leading-dot": "The name cannot start with a dot.",
43377
+ "too-long": "The name is too long."
43378
+ }
43379
+ },
43380
+ ja: {
43381
+ title: "作業ツリー",
43382
+ ariaLabel: "git の作業ツリー",
43383
+ loading: "作業ツリーを読み込んでいます…",
43384
+ loadFailed: "作業ツリーを読み込めませんでした。",
43385
+ empty: "作業ツリーがありません。",
43386
+ refresh: "再読み込み",
43387
+ refreshTitle: "一覧を読み直す",
43388
+ count: (n2) => `${n2} 本`,
43389
+ baseUnknown: "比較の基準になるブランチが見つかりません",
43390
+ gitignoreHint: "このディレクトリは git から未追跡に見えます。.worktrees/ を .gitignore に入れると git status に出なくなります。",
43391
+ badges: {
43392
+ current: "このフォルダ",
43393
+ currentTitle: "この code-viewer が開いているフォルダです",
43394
+ detached: "ブランチなし",
43395
+ detachedTitle: "どのブランチにも紐づいていません(detached HEAD)",
43396
+ bare: "bare",
43397
+ bareTitle: "作業ファイルを持たない保管用のリポジトリです",
43398
+ locked: "ロック中",
43399
+ prunable: "掃除できます",
43400
+ prunableTitle: "フォルダが無い等で管理情報だけ残っています",
43401
+ missing: "フォルダがありません",
43402
+ running: "起動中",
43403
+ runningTitle: "このフォルダ専用の code-viewer が別ポートで動いています"
43404
+ },
43405
+ diverge: {
43406
+ ahead: (n2, base2) => `${base2} より ${n2} コミット進んでいます`,
43407
+ behind: (n2, base2) => `${base2} より ${n2} コミット遅れています`,
43408
+ even: (base2) => `${base2} と同じ地点です`,
43409
+ notComparable: "比較なし"
43410
+ },
43411
+ merge: {
43412
+ clean: "そのままマージできます",
43413
+ conflict: (n2) => `マージすると ${n2} ファイルで衝突します`,
43414
+ unknown: "マージできるか確かめられませんでした",
43415
+ conflictListLabel: "衝突するファイル"
43416
+ },
43417
+ files: {
43418
+ heading: (n2) => `変更 ${n2} 件`,
43419
+ none: "変更はありません。",
43420
+ uncommitted: "未コミット",
43421
+ committed: "コミット済み・未マージ",
43422
+ truncated: (shown, total) => `${total} 件のうち ${shown} 件を表示`,
43423
+ // 行の中に置くので短くする。誰と重なっているかは title に入る。
43424
+ overlapMark: "重複",
43425
+ overlapTitle: (others) => `同じファイルを触っている: ${others.join("、")}`,
43426
+ statusTitles: JA_STATUS_TITLES
43427
+ },
43428
+ overlaps: {
43429
+ heading: (n2) => `${n2} 個のファイルを 2 本以上が触っています`,
43430
+ intro: "どれか 1 本をマージすると、残りはこのファイルで衝突します。",
43431
+ entry: (path, worktrees) => `${path} — ${worktrees.join("、")}`
43432
+ },
43433
+ panes: {
43434
+ worktrees: "作業ツリー",
43435
+ files: "ファイル",
43436
+ diff: "差分",
43437
+ filterWorktrees: "作業ツリーを絞り込み…",
43438
+ filterFiles: "ファイルを絞り込み…",
43439
+ noWorktreeMatch: "該当する作業ツリーがありません。",
43440
+ noFileMatch: "該当するファイルがありません。",
43441
+ selectWorktree: "作業ツリーを選ぶと、何を触っているかが出ます。",
43442
+ selectFile: "ファイルを選ぶと差分が出ます。",
43443
+ diffLoading: "差分を読み込んでいます…",
43444
+ diffEmpty: "テキストの差分はありません(バイナリか、変更なし)。",
43445
+ diffFailed: "差分を読み込めませんでした。",
43446
+ diffTruncated: (shown, total) => `${total} 個のうち ${shown} 個のかたまりを表示しています。全部見るには、その作業ツリーを別タブで見てください`
43447
+ },
43448
+ noCommit: "コミットなし",
43449
+ lastTouched: (when) => `最終更新 ${when}`,
43450
+ actions: {
43451
+ menuTitle: "この作業ツリーへの操作",
43452
+ menuFor: (name) => `${name} への操作`,
43453
+ openFolder: "フォルダを開く",
43454
+ openFolderTitle: "このフォルダをファイルマネージャで開きます",
43455
+ openFolderFailed: "そのフォルダを開けませんでした。",
43456
+ copyPath: "パスをコピー",
43457
+ copyPathTitle: "このフォルダの場所をコピーします",
43458
+ copyFailed: "クリップボードにコピーできませんでした。",
43459
+ stopServer: "サーバを止める",
43460
+ stopServerTitle: "このフォルダで動いている code-viewer を止めます",
43461
+ stopFailed: "サーバを止められませんでした。",
43462
+ copyServerUrl: "アドレスをコピー",
43463
+ copyServerUrlTitle: (url) => `${url} をコピーします`,
43464
+ copyMerge: "マージのコマンドをコピー",
43465
+ copyMergeTitle: (base2, branch) => `${branch} を ${base2} に取り込むコマンドをコピーします`
43466
+ },
43467
+ emptyDiff: {
43468
+ title: "まだ変更はありません。",
43469
+ body: (path) => `${path} でファイルを編集すると、ここに差分が出ます。`
43470
+ },
43471
+ intro: {
43472
+ cardTitle: "作業ツリー(git worktree)とは",
43473
+ cardWhat: "同じリポジトリを、ブランチを切り替えずに別フォルダでもう 1 つ開く仕組みです。",
43474
+ cardWhy: "main で作業しながら、別フォルダで修正用のブランチを開いておけます。2 つの作業を並べて進められます。",
43475
+ cardHow: "「作る」を押すと .worktrees/〈名前〉 にフォルダができ、指定したブランチがそこに展開されます。あとはそのフォルダで普通に編集してください。変更はこの画面に差分として出ます。",
43476
+ cardButton: "作業ツリーを作る",
43477
+ listNote: "いまはこのフォルダだけです。作業ツリーを作ると、ここに並びます。",
43478
+ overlapLegend: "⇄ = 他の作業ツリーも同じファイルを触っている"
43479
+ },
43480
+ open: "別タブで見る",
43481
+ openTitle: "このフォルダ専用の code-viewer を起動して新しいタブで開きます",
43482
+ opening: "起動中…",
43483
+ openFailed: "この作業ツリーを開けませんでした。",
43484
+ add: "作る",
43485
+ addTitle: "作業ツリーを新しく作る",
43486
+ addFailed: "作業ツリーを作れませんでした。",
43487
+ addDialog: {
43488
+ title: "作業ツリーを作る",
43489
+ intro: "ブランチを切り替えずに、別フォルダで 2 つの作業を並べて進められます。",
43490
+ nameLabel: "フォルダ名",
43491
+ namePlaceholder: "feature-x",
43492
+ branchLabel: "ブランチ",
43493
+ branchPlaceholder: "フォルダ名と同じ",
43494
+ branchHint: "既にあるブランチ名ならそれを開きます。無ければ、いまの地点から新しく作ります。",
43495
+ targetLabel: "作成先",
43496
+ targetPending: (parent) => `${parent}/…`,
43497
+ gitignoreLabel: "このフォルダと git status について",
43498
+ submit: "作る"
43499
+ },
43500
+ remove: "この作業ツリーを削除",
43501
+ removeTitle: "この作業ツリーをフォルダごと削除します",
43502
+ removeDialog: {
43503
+ title: "作業ツリーの削除",
43504
+ body: (name) => `作業ツリー「${name}」を削除しますか。`,
43505
+ diskNote: (path) => `フォルダ ${path} とその中身はディスクから消えます。元に戻せません。`,
43506
+ branchNote: (branch) => `ブランチ ${branch} と、コミット済みの内容は残ります。`,
43507
+ dirtyNote: (count) => `コミットしていない変更が ${count} 件あります。`,
43508
+ dirtyLose: "削除するとこれらの変更は失われます。",
43509
+ force: "変更が残っていても削除する",
43510
+ forceRequired: "変更を捨てて削除するには、チェックを入れてください。",
43511
+ missingBody: (name) => `作業ツリー「${name}」の登録を消しますか。`,
43512
+ missingNote: "フォルダは既にディスク上にありません。git の管理情報だけを消します。",
43513
+ lockedNote: "この登録はロックされているので、git はそのまま残します。先にロックを外してください。",
43514
+ missingOthers: (n2) => `フォルダが無くなっている他の登録 ${n2} 件も、同時に整理されます。`,
43515
+ submit: "削除する"
43516
+ },
43517
+ removeFailed: "作業ツリーを削除できませんでした。",
43518
+ cancel: "キャンセル",
43519
+ nameErrors: {
43520
+ empty: "名前を入力してください。",
43521
+ control: "制御文字は使えません。",
43522
+ separator: "パス区切りは使えません。",
43523
+ relative: "この名前は使えません。",
43524
+ "leading-dot": "ドットで始まる名前は使えません。",
43525
+ "too-long": "名前が長すぎます。"
43526
+ }
43527
+ }
43528
+ };
43529
+ function worktreeText(lang) {
43530
+ return TEXT3[lang];
43531
+ }
43532
+
43533
+ // web-src/core/worktree.ts
43534
+ var WORKTREE_NAME_MAX_LENGTH = 100;
43535
+ function worktreeNameError(name) {
43536
+ if (!name) return "empty";
43537
+ if (name.length > WORKTREE_NAME_MAX_LENGTH) return "too-long";
43538
+ for (const ch of name) {
43539
+ const code2 = ch.charCodeAt(0);
43540
+ if (code2 < 32 || code2 === 127) return "control";
43541
+ }
43542
+ if (name.includes("/") || name.includes("\\")) return "separator";
43543
+ if (name === "." || name === "..") return "relative";
43544
+ if (name.startsWith(".")) return "leading-dot";
43545
+ return null;
43546
+ }
43547
+ function worktreeBranchError(branch) {
43548
+ if (!branch) return "empty";
43549
+ if (branch.length > WORKTREE_NAME_MAX_LENGTH) return "too-long";
43550
+ for (const ch of branch) {
43551
+ const code2 = ch.charCodeAt(0);
43552
+ if (code2 < 32 || code2 === 127) return "control";
43553
+ }
43554
+ if (branch.startsWith("-") || branch.includes("..")) return "relative";
43555
+ return null;
43556
+ }
43557
+
43558
+ // web-src/views/context-menu.ts
43559
+ var open = null;
43560
+ function closeContextMenu() {
43561
+ if (!open) return;
43562
+ const closing = open;
43563
+ open = null;
43564
+ closing.cleanup();
43565
+ closing.element.remove();
43566
+ }
43567
+ function showContextMenu(anchor, items) {
43568
+ closeContextMenu();
43569
+ const menu = document.createElement("div");
43570
+ menu.className = "gdp-context-menu";
43571
+ menu.setAttribute("role", "menu");
43572
+ for (const item of items) {
43573
+ if (item.kind === "separator") {
43574
+ const line = document.createElement("hr");
43575
+ line.className = "gdp-context-menu-sep";
43576
+ menu.appendChild(line);
43577
+ continue;
43578
+ }
43579
+ const button = document.createElement("button");
43580
+ button.type = "button";
43581
+ button.setAttribute("role", "menuitem");
43582
+ button.textContent = item.label;
43583
+ if (item.title) button.title = item.title;
43584
+ if (item.danger) button.classList.add("danger");
43585
+ button.disabled = !!item.disabled;
43586
+ button.addEventListener("click", () => {
43587
+ closeContextMenu();
43588
+ item.onSelect();
43589
+ });
43590
+ menu.appendChild(button);
43591
+ }
43592
+ document.body.appendChild(menu);
43593
+ const rect = menu.getBoundingClientRect();
43594
+ const from = anchor.getBoundingClientRect();
43595
+ const left = Math.min(
43596
+ from.right - rect.width,
43597
+ window.innerWidth - rect.width - 8
43598
+ );
43599
+ const top = Math.min(from.bottom + 4, window.innerHeight - rect.height - 8);
43600
+ menu.style.left = `${Math.max(8, left)}px`;
43601
+ menu.style.top = `${Math.max(8, top)}px`;
43602
+ const onPointerDown = (event) => {
43603
+ if (menu.contains(event.target)) return;
43604
+ closeContextMenu();
43605
+ };
43606
+ const onKeyDown = (event) => {
43607
+ if (event.key !== "Escape") return;
43608
+ event.stopPropagation();
43609
+ closeContextMenu();
43610
+ anchor.focus();
43611
+ };
43612
+ const onScroll = () => closeContextMenu();
43613
+ document.addEventListener("pointerdown", onPointerDown, true);
43614
+ document.addEventListener("keydown", onKeyDown, true);
43615
+ window.addEventListener("scroll", onScroll, true);
43616
+ window.addEventListener("resize", onScroll);
43617
+ open = {
43618
+ element: menu,
43619
+ cleanup() {
43620
+ document.removeEventListener("pointerdown", onPointerDown, true);
43621
+ document.removeEventListener("keydown", onKeyDown, true);
43622
+ window.removeEventListener("scroll", onScroll, true);
43623
+ window.removeEventListener("resize", onScroll);
43624
+ }
43625
+ };
43626
+ menu.querySelector("button:not(:disabled)")?.focus();
43627
+ }
43628
+
43629
+ // web-src/views/worktree-view.ts
43630
+ var SSE_REFRESH_DELAY_MS = 400;
43631
+ var DIFF_PREFETCH_MARGIN = "600px";
43632
+ var ACTION_HEADERS = {
43633
+ "Content-Type": "application/json",
43634
+ "X-Code-Viewer-Action": "1"
43635
+ };
43636
+ async function postWorktreeAction(path, body) {
43637
+ const res = await fetch(path, {
43638
+ method: "POST",
43639
+ headers: ACTION_HEADERS,
43640
+ body: JSON.stringify(body)
43641
+ });
43642
+ if (!res.ok) throw new Error(await res.text() || `${res.status}`);
43643
+ return await res.json();
43644
+ }
43645
+ function el(tag, className, text3) {
43646
+ const node = document.createElement(tag);
43647
+ if (className) node.className = className;
43648
+ if (text3 !== void 0) node.textContent = text3;
43649
+ return node;
43650
+ }
43651
+ function fileKey(file) {
43652
+ return `${file.origin}:${file.path}`;
43653
+ }
43654
+ function chevronSvg() {
43655
+ return iconSvg("octicon-chevron-down", CHEVRON_DOWN_16_PATH);
43656
+ }
43657
+ function folderSvg(collapsed) {
43658
+ return iconSvg(
43659
+ collapsed ? "octicon-file-directory-fill" : "octicon-file-directory-open-fill",
43660
+ collapsed ? FOLDER_ICON_PATHS.closed : FOLDER_ICON_PATHS.open
43661
+ );
43662
+ }
43663
+ function matches(haystack, needle) {
43664
+ return !needle || haystack.toLowerCase().includes(needle.toLowerCase());
43665
+ }
43666
+ function createWorktreeView(deps) {
43667
+ let mounted = false;
43668
+ let lifecycle = 0;
43669
+ let acceptedServerGeneration = 0;
43670
+ let data = null;
43671
+ let message = "";
43672
+ let messageIsError = false;
43673
+ let busyPath = "";
43674
+ let sseTimer = null;
43675
+ let refreshRequested = false;
43676
+ let refreshLoop = null;
43677
+ let worktreeFilter = "";
43678
+ let fileFilter = "";
43679
+ let diffFor = null;
43680
+ let restoredRouteKey = null;
43681
+ let observer = null;
43682
+ const listPanel = document.getElementById("worktree-panel");
43683
+ function text3() {
43684
+ return deps.getText();
43685
+ }
43686
+ function route() {
43687
+ const current = deps.getRoute();
43688
+ return current.screen === "worktree" ? current : null;
43689
+ }
43690
+ function setMessage(next, isError = false) {
43691
+ message = next;
43692
+ messageIsError = isError;
43693
+ }
43694
+ function isCurrent(seq) {
43695
+ return mounted && seq === lifecycle && route() !== null;
43696
+ }
43697
+ const worktreeFilterInput = (() => {
43698
+ const input2 = el("input", "history-filter");
43699
+ input2.type = "search";
43700
+ input2.autocomplete = "off";
43701
+ input2.addEventListener("input", () => {
43702
+ worktreeFilter = input2.value;
43703
+ renderList();
43704
+ });
43705
+ return input2;
43706
+ })();
43707
+ function sidebarFilter() {
43708
+ return document.querySelector("#sb-filter");
43709
+ }
43710
+ function onSidebarFilter() {
43711
+ fileFilter = sidebarFilter()?.value || "";
43712
+ renderFiles();
43713
+ }
43714
+ function onSidebarViewToggle() {
43715
+ window.setTimeout(() => renderFiles(), 0);
43716
+ }
43717
+ function setAllDirsCollapsed(collapsed) {
43718
+ const list2 = document.getElementById("filelist");
43719
+ if (!list2) return;
43720
+ for (const dir of list2.querySelectorAll(".tree-dir")) {
43721
+ dir.classList.toggle("collapsed", collapsed);
43722
+ const icon = dir.querySelector(":scope > .dir-icon");
43723
+ if (icon) icon.innerHTML = folderSvg(collapsed);
43724
+ }
43725
+ }
43726
+ function onExpandAll() {
43727
+ setAllDirsCollapsed(false);
43728
+ }
43729
+ function onCollapseAll() {
43730
+ setAllDirsCollapsed(true);
43731
+ }
43732
+ function sidebarViewButtons() {
43733
+ return Array.from(
43734
+ document.querySelectorAll(".sb-view-seg button")
43735
+ );
43736
+ }
43737
+ function mount() {
43738
+ if (mounted || !listPanel) return;
43739
+ document.getElementById("empty")?.classList.add("hidden");
43740
+ document.getElementById("history-commit-info")?.setAttribute("hidden", "true");
43741
+ listPanel.hidden = false;
43742
+ mounted = true;
43743
+ document.body.classList.add("gdp-worktree-page");
43744
+ sidebarFilter()?.addEventListener("input", onSidebarFilter);
43745
+ document.getElementById("filelist")?.addEventListener("click", onFileListClick);
43746
+ for (const button of sidebarViewButtons()) {
43747
+ button.addEventListener("click", onSidebarViewToggle);
43748
+ }
43749
+ document.getElementById("sb-expand-all")?.addEventListener("click", onExpandAll);
43750
+ document.getElementById("sb-collapse-all")?.addEventListener("click", onCollapseAll);
43751
+ deps.setPageMode();
43752
+ deps.syncHeaderMenu();
43753
+ }
43754
+ function suspend() {
43755
+ lifecycle++;
43756
+ closeContextMenu();
43757
+ observer?.disconnect();
43758
+ observer = null;
43759
+ diffFor = null;
43760
+ restoredRouteKey = null;
43761
+ if (sseTimer !== null) {
43762
+ window.clearTimeout(sseTimer);
43763
+ sseTimer = null;
43764
+ }
43765
+ refreshRequested = false;
43766
+ if (listPanel) {
43767
+ listPanel.hidden = true;
43768
+ listPanel.replaceChildren();
43769
+ }
43770
+ sidebarFilter()?.removeEventListener("input", onSidebarFilter);
43771
+ document.getElementById("filelist")?.removeEventListener("click", onFileListClick);
43772
+ for (const button of sidebarViewButtons()) {
43773
+ button.removeEventListener("click", onSidebarViewToggle);
43774
+ }
43775
+ document.getElementById("sb-expand-all")?.removeEventListener("click", onExpandAll);
43776
+ document.getElementById("sb-collapse-all")?.removeEventListener("click", onCollapseAll);
43777
+ document.getElementById("filelist")?.replaceChildren();
43778
+ document.getElementById("diff")?.replaceChildren();
43779
+ document.body.classList.remove("gdp-worktree-page");
43780
+ mounted = false;
43781
+ }
43782
+ function selectedWorktree() {
43783
+ const id = route()?.wt;
43784
+ if (!id || !data) return null;
43785
+ return data.worktrees.find((item) => item.id === id) || null;
43786
+ }
43787
+ function worktreeLabel(id) {
43788
+ const item = data?.worktrees.find((candidate) => candidate.id === id);
43789
+ if (!item) return id;
43790
+ const sameName = data?.worktrees.filter(
43791
+ (candidate) => candidate.name === item.name
43792
+ );
43793
+ return sameName && sameName.length > 1 ? `${item.name} (${item.displayPath})` : item.name;
43794
+ }
43795
+ function navigate(next, replace2 = false) {
43796
+ const current = route();
43797
+ if (!current) return;
43798
+ deps.setRoute(
43799
+ {
43800
+ screen: "worktree",
43801
+ ...current.wt ? { wt: current.wt } : {},
43802
+ ...current.file ? { file: current.file } : {},
43803
+ ...current.origin ? { origin: current.origin } : {},
43804
+ ...next,
43805
+ range: deps.currentRange()
43806
+ },
43807
+ replace2
43808
+ );
43809
+ }
43810
+ async function refreshOnce() {
43811
+ if (!mounted || !route()) return;
43812
+ const seq = ++lifecycle;
43813
+ if (!data) setMessage(text3().loading);
43814
+ renderList();
43815
+ deps.setStatus("refreshing");
43816
+ try {
43817
+ const next = await deps.trackLoad(
43818
+ fetch("/_worktree/list").then(async (res) => {
43819
+ if (!res.ok) throw new Error(await res.text() || `${res.status}`);
43820
+ return await res.json();
43821
+ })
43822
+ );
43823
+ if (!isCurrent(seq)) return;
43824
+ if (!Number.isInteger(next.generation) || next.generation < acceptedServerGeneration) {
43825
+ throw new Error(
43826
+ `stale worktree response generation ${next.generation}; current is ${acceptedServerGeneration}`
43827
+ );
43828
+ }
43829
+ acceptedServerGeneration = next.generation;
43830
+ data = next;
43831
+ setMessage(next.error || "", !!next.error);
43832
+ deps.setStatus(next.error ? "error" : "live");
43833
+ } catch (error2) {
43834
+ if (!isCurrent(seq)) return;
43835
+ setMessage(
43836
+ error2 instanceof Error ? error2.message : text3().loadFailed,
43837
+ true
43838
+ );
43839
+ deps.setStatus("error");
43840
+ } finally {
43841
+ if (isCurrent(seq)) {
43842
+ diffFor = null;
43843
+ render();
43844
+ }
43845
+ }
43846
+ }
43847
+ function refresh() {
43848
+ if (!mounted || !route()) return Promise.resolve();
43849
+ refreshRequested = true;
43850
+ if (refreshLoop) return refreshLoop;
43851
+ const loop = (async () => {
43852
+ while (refreshRequested && mounted && route()) {
43853
+ refreshRequested = false;
43854
+ await refreshOnce();
43855
+ }
43856
+ })();
43857
+ const tracked = loop.finally(() => {
43858
+ if (refreshLoop === tracked) refreshLoop = null;
43859
+ });
43860
+ refreshLoop = tracked;
43861
+ return tracked;
43862
+ }
43863
+ function openBlankTab() {
43864
+ try {
43865
+ const tab = window.open("", "_blank");
43866
+ if (tab) tab.opener = null;
43867
+ return tab;
43868
+ } catch {
43869
+ return null;
43870
+ }
43871
+ }
43872
+ async function openWorktree(item) {
43873
+ if (busyPath) return;
43874
+ const seq = lifecycle;
43875
+ busyPath = item.path;
43876
+ setMessage(text3().opening);
43877
+ renderList();
43878
+ const tab = openBlankTab();
43879
+ try {
43880
+ const result = await deps.trackLoad(
43881
+ postWorktreeAction("/_worktree/open", { path: item.path })
43882
+ );
43883
+ const url = result.url || "";
43884
+ if (!url) throw new Error(text3().openFailed);
43885
+ if (tab) tab.location.href = url;
43886
+ if (isCurrent(seq)) setMessage(tab ? "" : url, !tab);
43887
+ } catch (error2) {
43888
+ tab?.close();
43889
+ if (isCurrent(seq)) {
43890
+ setMessage(
43891
+ error2 instanceof Error ? error2.message : text3().openFailed,
43892
+ true
43893
+ );
43894
+ }
43895
+ } finally {
43896
+ busyPath = "";
43897
+ if (isCurrent(seq)) await refresh();
43898
+ }
43899
+ }
43900
+ function labeledInput(label, placeholder, hint) {
43901
+ const wrap = document.createElement("label");
43902
+ wrap.className = "worktree-field";
43903
+ wrap.appendChild(el("span", "", label));
43904
+ const input2 = el("input", "gdp-dialog-input");
43905
+ input2.type = "text";
43906
+ input2.placeholder = placeholder;
43907
+ wrap.appendChild(input2);
43908
+ if (hint) wrap.appendChild(el("span", "worktree-hint", hint));
43909
+ return { wrap, input: input2 };
43910
+ }
43911
+ async function addWorktree() {
43912
+ const seq = lifecycle;
43913
+ const t2 = text3();
43914
+ const body = el("div", "worktree-form");
43915
+ body.appendChild(el("p", "worktree-hint", t2.addDialog.intro));
43916
+ const name = labeledInput(
43917
+ t2.addDialog.nameLabel,
43918
+ t2.addDialog.namePlaceholder
43919
+ );
43920
+ const branch = labeledInput(
43921
+ t2.addDialog.branchLabel,
43922
+ t2.addDialog.branchPlaceholder,
43923
+ t2.addDialog.branchHint
43924
+ );
43925
+ body.append(name.wrap, branch.wrap);
43926
+ const parent = data?.addParent || "";
43927
+ if (parent) {
43928
+ const targetRow = el("div", "worktree-target");
43929
+ targetRow.appendChild(
43930
+ el("span", "worktree-target-label", t2.addDialog.targetLabel)
43931
+ );
43932
+ const targetPath = el("span", "worktree-target-path");
43933
+ targetRow.appendChild(targetPath);
43934
+ const hint = el("span", "worktree-hint-mark", "?");
43935
+ hint.title = t2.gitignoreHint;
43936
+ hint.tabIndex = 0;
43937
+ hint.setAttribute("role", "note");
43938
+ hint.setAttribute(
43939
+ "aria-label",
43940
+ `${t2.addDialog.gitignoreLabel}: ${t2.gitignoreHint}`
43941
+ );
43942
+ targetRow.appendChild(hint);
43943
+ body.appendChild(targetRow);
43944
+ const syncTarget = () => {
43945
+ const value = name.input.value.trim();
43946
+ targetPath.textContent = value ? `${parent}/${value}` : t2.addDialog.targetPending(parent);
43947
+ targetPath.title = targetPath.textContent;
43948
+ };
43949
+ name.input.addEventListener("input", syncTarget);
43950
+ syncTarget();
43951
+ }
43952
+ const submitted = await showFormDialog({
43953
+ title: t2.addDialog.title,
43954
+ body,
43955
+ submitLabel: t2.addDialog.submit,
43956
+ cancelLabel: t2.cancel,
43957
+ focusTarget: name.input,
43958
+ validate: () => {
43959
+ const nameError = worktreeNameError(name.input.value.trim());
43960
+ if (nameError) return t2.nameErrors[nameError];
43961
+ const raw = branch.input.value.trim();
43962
+ if (!raw) return null;
43963
+ const branchError = worktreeBranchError(raw);
43964
+ return branchError ? t2.nameErrors[branchError] : null;
43965
+ },
43966
+ submit: () => ({
43967
+ name: name.input.value.trim(),
43968
+ branch: branch.input.value.trim()
43969
+ })
43970
+ });
43971
+ if (!submitted) return;
43972
+ if (!isCurrent(seq)) return;
43973
+ let createdPath = "";
43974
+ try {
43975
+ const result = await deps.trackLoad(
43976
+ postWorktreeAction("/_worktree/add", submitted)
43977
+ );
43978
+ if (isCurrent(seq)) setMessage("");
43979
+ createdPath = result.path || "";
43980
+ } catch (error2) {
43981
+ if (isCurrent(seq)) {
43982
+ setMessage(error2 instanceof Error ? error2.message : t2.addFailed, true);
43983
+ }
43984
+ }
43985
+ if (isCurrent(seq) && createdPath) {
43986
+ navigate({ wt: createdPath });
43987
+ }
43988
+ if (isCurrent(seq)) await refresh();
43989
+ }
43990
+ async function removeWorktree(item) {
43991
+ if (busyPath) return;
43992
+ const seq = lifecycle;
43993
+ const t2 = text3();
43994
+ const body = el("div", "worktree-form");
43995
+ if (item.missing) {
43996
+ body.appendChild(el("p", "", t2.removeDialog.missingBody(item.name)));
43997
+ body.appendChild(el("p", "worktree-hint", t2.removeDialog.missingNote));
43998
+ if (item.locked) {
43999
+ body.appendChild(el("p", "worktree-warn", t2.removeDialog.lockedNote));
44000
+ }
44001
+ const otherMissing = (data?.worktrees || []).filter(
44002
+ (candidate) => candidate.missing && !candidate.locked && candidate.id !== item.id
44003
+ ).length;
44004
+ if (otherMissing > 0) {
44005
+ body.appendChild(
44006
+ el("p", "worktree-hint", t2.removeDialog.missingOthers(otherMissing))
44007
+ );
44008
+ }
44009
+ } else {
44010
+ body.appendChild(el("p", "", t2.removeDialog.body(item.name)));
44011
+ body.appendChild(el("p", "", t2.removeDialog.diskNote(item.path)));
44012
+ }
44013
+ if (item.branch) {
44014
+ body.appendChild(
44015
+ el("p", "worktree-hint", t2.removeDialog.branchNote(item.branch))
44016
+ );
44017
+ }
44018
+ let force = null;
44019
+ if (!item.missing && item.changedCount > 0) {
44020
+ const warn = el("p", "worktree-warn");
44021
+ warn.appendChild(
44022
+ el("span", "", `⚠ ${t2.removeDialog.dirtyNote(item.changedCount)}`)
44023
+ );
44024
+ warn.appendChild(document.createElement("br"));
44025
+ warn.appendChild(el("span", "", t2.removeDialog.dirtyLose));
44026
+ body.appendChild(warn);
44027
+ const forceWrap = document.createElement("label");
44028
+ forceWrap.className = "worktree-check";
44029
+ force = document.createElement("input");
44030
+ force.type = "checkbox";
44031
+ forceWrap.append(force, el("span", "", t2.removeDialog.force));
44032
+ body.appendChild(forceWrap);
44033
+ }
44034
+ const submitted = await showFormDialog({
44035
+ title: t2.removeDialog.title,
44036
+ body,
44037
+ submitLabel: t2.removeDialog.submit,
44038
+ cancelLabel: t2.cancel,
44039
+ // フォルダごと消える不可逆の操作なので、確定は常に危険色。
44040
+ danger: true,
44041
+ validate: () => force && !force.checked ? t2.removeDialog.forceRequired : null,
44042
+ submit: () => ({ force: force?.checked ?? false })
44043
+ });
44044
+ if (!submitted) return;
44045
+ if (!isCurrent(seq)) return;
44046
+ busyPath = item.path;
44047
+ renderList();
44048
+ try {
44049
+ await deps.trackLoad(
44050
+ postWorktreeAction("/_worktree/remove", {
44051
+ path: item.path,
44052
+ force: submitted.force
44053
+ })
44054
+ );
44055
+ if (isCurrent(seq)) setMessage("");
44056
+ if (isCurrent(seq) && route()?.wt === item.id) {
44057
+ navigate({ wt: void 0, file: void 0, origin: void 0 }, true);
44058
+ }
44059
+ } catch (error2) {
44060
+ if (isCurrent(seq)) {
44061
+ setMessage(
44062
+ error2 instanceof Error ? error2.message : t2.removeFailed,
44063
+ true
44064
+ );
44065
+ }
44066
+ } finally {
44067
+ busyPath = "";
44068
+ if (isCurrent(seq)) await refresh();
44069
+ }
44070
+ }
44071
+ function overlapOthers(item, file) {
44072
+ const paths = new Set([file.path, file.oldPath].filter(Boolean));
44073
+ const ownerIds = new Set(
44074
+ (data?.overlaps || []).filter((overlap) => paths.has(overlap.path)).flatMap((overlap) => overlap.worktreeIds)
44075
+ );
44076
+ return [...ownerIds].filter((id) => id !== item.id).map((id) => worktreeLabel(id));
44077
+ }
44078
+ function divergenceSummary(item) {
44079
+ const t2 = text3();
44080
+ const divergence = item.divergence;
44081
+ if (!divergence) return t2.diverge.notComparable;
44082
+ const parts = [];
44083
+ if (divergence.mergeState === "clean") {
44084
+ parts.push(t2.merge.clean);
44085
+ } else if (divergence.mergeState === "conflict") {
44086
+ parts.push(t2.merge.conflict(divergence.conflicts.length));
44087
+ } else {
44088
+ parts.push(t2.merge.unknown);
44089
+ }
44090
+ if (divergence.ahead > 0) {
44091
+ parts.push(t2.diverge.ahead(divergence.ahead, divergence.base));
44092
+ }
44093
+ if (divergence.behind > 0) {
44094
+ parts.push(t2.diverge.behind(divergence.behind, divergence.base));
44095
+ }
44096
+ if (!divergence.ahead && !divergence.behind) {
44097
+ parts.push(t2.diverge.even(divergence.base));
44098
+ }
44099
+ return parts.join(" · ");
44100
+ }
44101
+ function worktreeBadges(item) {
44102
+ const t2 = text3();
44103
+ const badges = [];
44104
+ if (item.current) {
44105
+ badges.push({ label: t2.badges.current, title: t2.badges.currentTitle });
44106
+ }
44107
+ if (item.serverUrl) {
44108
+ badges.push({ label: t2.badges.running, title: t2.badges.runningTitle });
44109
+ }
44110
+ if (item.missing) badges.push({ label: t2.badges.missing, title: "" });
44111
+ if (item.bare) {
44112
+ badges.push({ label: t2.badges.bare, title: t2.badges.bareTitle });
44113
+ }
44114
+ if (item.locked) {
44115
+ badges.push({ label: t2.badges.locked, title: item.lockedReason });
44116
+ }
44117
+ if (item.prunable) {
44118
+ badges.push({ label: t2.badges.prunable, title: t2.badges.prunableTitle });
44119
+ }
44120
+ return badges;
44121
+ }
44122
+ function headButton(label, title, onClick) {
44123
+ const button = el("button", "gdp-btn gdp-btn-sm worktree-head-btn", label);
44124
+ button.type = "button";
44125
+ button.title = title;
44126
+ button.addEventListener("click", onClick);
44127
+ return button;
44128
+ }
44129
+ function openFolderButton(item, withLabel) {
44130
+ const arg = openPathArg(item);
44131
+ if (arg === null) return null;
44132
+ const t2 = text3();
44133
+ const button = deps.createOpenPathButton(
44134
+ arg,
44135
+ "directory",
44136
+ t2.actions.openFolderTitle
44137
+ );
44138
+ if (withLabel) {
44139
+ button.className = "gdp-btn gdp-btn-sm gdp-open-path";
44140
+ button.textContent = t2.actions.openFolder;
44141
+ }
44142
+ return button;
44143
+ }
44144
+ function copyButton(value, title, label) {
44145
+ const button = el(
44146
+ "button",
44147
+ label ? "gdp-btn gdp-btn-sm gdp-copy-path" : "gdp-file-header-icon gdp-copy-path",
44148
+ label
44149
+ );
44150
+ button.type = "button";
44151
+ button.title = title;
44152
+ button.setAttribute("aria-label", title);
44153
+ if (!label) button.innerHTML = iconSvg("octicon-copy", COPY_16_PATHS);
44154
+ button.addEventListener("click", async (event) => {
44155
+ event.stopPropagation();
44156
+ button.classList.remove("copied", "failed");
44157
+ button.classList.add(await copyText(value) ? "copied" : "failed");
44158
+ window.setTimeout(
44159
+ () => button.classList.remove("copied", "failed"),
44160
+ 1200
44161
+ );
44162
+ });
44163
+ return button;
44164
+ }
44165
+ async function runAction(run, failure) {
44166
+ const seq = lifecycle;
44167
+ if (await run()) return;
44168
+ if (!isCurrent(seq)) return;
44169
+ setMessage(failure, true);
44170
+ renderList();
44171
+ }
44172
+ async function copyText(value) {
44173
+ try {
44174
+ await navigator.clipboard.writeText(value);
44175
+ return true;
44176
+ } catch (error2) {
44177
+ console.error("[code-viewer] failed to copy to clipboard", error2);
44178
+ return false;
44179
+ }
44180
+ }
44181
+ function copyPathButton(item, withLabel) {
44182
+ const t2 = text3();
44183
+ return copyButton(
44184
+ item.path,
44185
+ t2.actions.copyPathTitle,
44186
+ withLabel ? t2.actions.copyPath : void 0
44187
+ );
44188
+ }
44189
+ function mergeCommand(item) {
44190
+ const divergence = item.divergence;
44191
+ if (!divergence || divergence.mergeState !== "clean") return null;
44192
+ if (!item.branch || !divergence.base) return null;
44193
+ return {
44194
+ base: divergence.base,
44195
+ branch: item.branch,
44196
+ command: `git switch ${divergence.base} && git merge ${item.branch}`
44197
+ };
44198
+ }
44199
+ function copyMergeButton(item) {
44200
+ const merge = mergeCommand(item);
44201
+ if (!merge) return null;
44202
+ const t2 = text3();
44203
+ return copyButton(
44204
+ merge.command,
44205
+ t2.actions.copyMergeTitle(merge.base, merge.branch)
44206
+ );
44207
+ }
44208
+ async function stopWorktreeServer(item) {
44209
+ if (busyPath) return;
44210
+ const seq = lifecycle;
44211
+ busyPath = item.path;
44212
+ renderList();
44213
+ try {
44214
+ await deps.trackLoad(
44215
+ postWorktreeAction("/_worktree/stop", { path: item.path })
44216
+ );
44217
+ if (isCurrent(seq)) setMessage("");
44218
+ } catch (error2) {
44219
+ if (isCurrent(seq)) {
44220
+ setMessage(
44221
+ error2 instanceof Error ? error2.message : text3().actions.stopFailed,
44222
+ true
44223
+ );
44224
+ }
44225
+ } finally {
44226
+ busyPath = "";
44227
+ if (isCurrent(seq)) await refresh();
44228
+ }
44229
+ }
44230
+ function openPathArg(item) {
44231
+ const shown = item.displayPath;
44232
+ if (shown === ".") return "";
44233
+ if (!shown || shown.startsWith("/") || shown.startsWith("\\")) return null;
44234
+ return shown;
44235
+ }
44236
+ function rowMenuItems(item) {
44237
+ const t2 = text3();
44238
+ const items = [];
44239
+ if (!item.missing && !item.bare) {
44240
+ const openArg = openPathArg(item);
44241
+ if (openArg !== null) {
44242
+ items.push({
44243
+ label: t2.actions.openFolder,
44244
+ title: t2.actions.openFolderTitle,
44245
+ onSelect: () => {
44246
+ void runAction(
44247
+ () => deps.openPathInOs(openArg, "directory"),
44248
+ t2.actions.openFolderFailed
44249
+ );
44250
+ }
44251
+ });
44252
+ }
44253
+ items.push({
44254
+ label: t2.actions.copyPath,
44255
+ title: t2.actions.copyPathTitle,
44256
+ onSelect: () => {
44257
+ void runAction(() => copyText(item.path), t2.actions.copyFailed);
44258
+ }
44259
+ });
44260
+ items.push({
44261
+ label: t2.open,
44262
+ title: t2.openTitle,
44263
+ disabled: !!busyPath,
44264
+ onSelect: () => {
44265
+ void openWorktree(item);
44266
+ }
44267
+ });
44268
+ }
44269
+ if (item.serverUrl) {
44270
+ items.push({
44271
+ label: t2.actions.copyServerUrl,
44272
+ title: t2.actions.copyServerUrlTitle(item.serverUrl),
44273
+ onSelect: () => {
44274
+ void runAction(() => copyText(item.serverUrl), t2.actions.copyFailed);
44275
+ }
44276
+ });
44277
+ }
44278
+ if (item.serverUrl && !item.current) {
44279
+ items.push({
44280
+ label: t2.actions.stopServer,
44281
+ title: t2.actions.stopServerTitle,
44282
+ disabled: !!busyPath,
44283
+ onSelect: () => {
44284
+ void stopWorktreeServer(item);
44285
+ }
44286
+ });
44287
+ }
44288
+ const merge = mergeCommand(item);
44289
+ if (merge) {
44290
+ items.push({
44291
+ label: t2.actions.copyMerge,
44292
+ title: t2.actions.copyMergeTitle(merge.base, merge.branch),
44293
+ onSelect: () => {
44294
+ void runAction(() => copyText(merge.command), t2.actions.copyFailed);
44295
+ }
44296
+ });
44297
+ }
44298
+ if (!item.current) {
44299
+ if (items.length) items.push({ kind: "separator" });
44300
+ items.push({
44301
+ label: t2.remove,
44302
+ title: t2.removeTitle,
44303
+ danger: true,
44304
+ disabled: !!busyPath,
44305
+ onSelect: () => {
44306
+ void removeWorktree(item);
44307
+ }
44308
+ });
44309
+ }
44310
+ return items;
44311
+ }
44312
+ function rowMenuButton(item) {
44313
+ const items = rowMenuItems(item);
44314
+ if (!items.length) return null;
44315
+ const t2 = text3();
44316
+ const button = el("button", "worktree-row-menu");
44317
+ button.type = "button";
44318
+ button.title = t2.actions.menuTitle;
44319
+ button.setAttribute("aria-label", t2.actions.menuFor(item.name));
44320
+ button.setAttribute("aria-haspopup", "menu");
44321
+ button.innerHTML = iconSvg("octicon-kebab-horizontal", KEBAB_16_PATH);
44322
+ button.addEventListener("click", (event) => {
44323
+ event.stopPropagation();
44324
+ showContextMenu(button, rowMenuItems(item));
44325
+ });
44326
+ return button;
44327
+ }
44328
+ function note(body, isError = false) {
44329
+ const node = el("div", "history-status", body);
44330
+ node.hidden = false;
44331
+ if (isError) {
44332
+ node.setAttribute("role", "alert");
44333
+ node.style.color = "var(--danger)";
44334
+ }
44335
+ return node;
44336
+ }
44337
+ function renderList() {
44338
+ if (!listPanel) return;
44339
+ const t2 = text3();
44340
+ listPanel.replaceChildren();
44341
+ const head = el("div", "history-head");
44342
+ head.appendChild(el("span", "history-title", t2.panes.worktrees));
44343
+ head.appendChild(
44344
+ headButton(t2.refresh, t2.refreshTitle, () => {
44345
+ void refresh();
44346
+ })
44347
+ );
44348
+ head.appendChild(
44349
+ headButton(t2.add, t2.addTitle, () => {
44350
+ void addWorktree();
44351
+ })
44352
+ );
44353
+ listPanel.appendChild(head);
44354
+ worktreeFilterInput.placeholder = t2.panes.filterWorktrees;
44355
+ const filterWrap = el("div", "history-filter-wrap");
44356
+ filterWrap.appendChild(worktreeFilterInput);
44357
+ listPanel.appendChild(filterWrap);
44358
+ if (data && !data.baseBranch) {
44359
+ listPanel.appendChild(note(t2.baseUnknown));
44360
+ }
44361
+ if (message) listPanel.appendChild(note(message, messageIsError));
44362
+ const overlaps = data?.overlaps || [];
44363
+ if (overlaps.length) {
44364
+ const banner = el("div", "history-banner");
44365
+ banner.hidden = false;
44366
+ banner.textContent = `${t2.overlaps.heading(overlaps.length)} — ${t2.overlaps.intro}`;
44367
+ banner.title = overlaps.map(
44368
+ (overlap) => t2.overlaps.entry(
44369
+ overlap.path,
44370
+ overlap.worktreeIds.map((id) => worktreeLabel(id))
44371
+ )
44372
+ ).join("\n");
44373
+ listPanel.appendChild(banner);
44374
+ }
44375
+ if (!data) {
44376
+ listPanel.appendChild(note(t2.loading));
44377
+ return;
44378
+ }
44379
+ if (!data.worktrees.length) {
44380
+ listPanel.appendChild(note(t2.empty));
44381
+ return;
44382
+ }
44383
+ const items = data.worktrees.filter(
44384
+ (item) => matches(item.name, worktreeFilter) || matches(item.branch, worktreeFilter) || matches(item.displayPath, worktreeFilter)
44385
+ );
44386
+ if (!items.length) {
44387
+ listPanel.appendChild(note(t2.panes.noWorktreeMatch));
44388
+ return;
44389
+ }
44390
+ const list2 = el("ol", "history-list");
44391
+ const selected = route()?.wt;
44392
+ for (const item of items) {
44393
+ const row = el("li", "history-item");
44394
+ row.dataset.wt = item.id;
44395
+ if (item.id === selected) row.classList.add("active");
44396
+ if (item.divergence?.mergeState === "conflict") {
44397
+ row.classList.add("worktree-conflict");
44398
+ }
44399
+ const head2 = el("span", "worktree-row-head");
44400
+ const subject = el("span", "subject", item.name);
44401
+ subject.title = item.path;
44402
+ head2.appendChild(subject);
44403
+ const badges = worktreeBadges(item);
44404
+ if (badges.length) {
44405
+ const wrap = el("span", "worktree-row-badges");
44406
+ badges.forEach((badge, index) => {
44407
+ if (index) wrap.appendChild(document.createTextNode(" · "));
44408
+ const node = el("span", "worktree-badge", badge.label);
44409
+ node.title = badge.title;
44410
+ wrap.appendChild(node);
44411
+ });
44412
+ head2.appendChild(wrap);
44413
+ }
44414
+ const menu = rowMenuButton(item);
44415
+ if (menu) head2.appendChild(menu);
44416
+ row.appendChild(head2);
44417
+ const pathLine = el("span", "worktree-row-path", item.path);
44418
+ pathLine.title = item.path;
44419
+ row.appendChild(pathLine);
44420
+ const meta = el("span", "meta2");
44421
+ const branchName = el("span", "sha", item.branch || t2.badges.detached);
44422
+ if (!item.branch) branchName.title = t2.badges.detachedTitle;
44423
+ meta.appendChild(branchName);
44424
+ meta.appendChild(
44425
+ el(
44426
+ "span",
44427
+ "author",
44428
+ item.fileCount ? t2.files.heading(item.fileCount) : t2.files.none
44429
+ )
44430
+ );
44431
+ if (item.lastCommit) {
44432
+ const parsed = Date.parse(item.lastCommit.when);
44433
+ const when = el(
44434
+ "span",
44435
+ "when",
44436
+ Number.isFinite(parsed) ? blameRelativeTime(Math.round(parsed / 1e3)) : item.lastCommit.when
44437
+ );
44438
+ when.title = Number.isFinite(parsed) ? `${item.lastCommit.subject}
44439
+ ${new Date(parsed).toLocaleString()}` : item.lastCommit.subject;
44440
+ meta.appendChild(when);
44441
+ }
44442
+ if (item.lastTouched) {
44443
+ const parsed = Date.parse(item.lastTouched);
44444
+ const when = el(
44445
+ "span",
44446
+ "when",
44447
+ Number.isFinite(parsed) ? t2.lastTouched(blameRelativeTime(Math.round(parsed / 1e3))) : t2.lastTouched(item.lastTouched)
44448
+ );
44449
+ when.title = Number.isFinite(parsed) ? new Date(parsed).toLocaleString() : item.lastTouched;
44450
+ meta.appendChild(when);
44451
+ }
44452
+ row.appendChild(meta);
44453
+ const second = el("span", "meta2");
44454
+ const summary = divergenceSummary(item);
44455
+ const summaryText = el("span", "author", summary);
44456
+ summaryText.title = summary;
44457
+ second.appendChild(summaryText);
44458
+ const merge = copyMergeButton(item);
44459
+ if (merge) second.appendChild(merge);
44460
+ row.appendChild(second);
44461
+ if (item.error) {
44462
+ const error2 = el("span", "meta2");
44463
+ const detail = el("span", "author", item.error);
44464
+ detail.style.color = "var(--danger)";
44465
+ error2.appendChild(detail);
44466
+ row.appendChild(error2);
44467
+ }
44468
+ list2.appendChild(row);
44469
+ }
44470
+ list2.addEventListener("click", (event) => {
44471
+ const row = event.target?.closest(
44472
+ ".history-item"
44473
+ );
44474
+ const id = row?.dataset.wt;
44475
+ if (!id) return;
44476
+ navigate({ wt: id, file: void 0, origin: void 0 });
44477
+ });
44478
+ listPanel.appendChild(list2);
44479
+ if (data.worktrees.length === 1) {
44480
+ listPanel.appendChild(note(t2.intro.listNote));
44481
+ }
44482
+ }
44483
+ function introCard() {
44484
+ const t2 = text3();
44485
+ const card = el("div", "worktree-intro");
44486
+ card.appendChild(el("p", "worktree-intro-title", t2.intro.cardTitle));
44487
+ card.appendChild(el("p", "", t2.intro.cardWhat));
44488
+ card.appendChild(el("p", "", t2.intro.cardWhy));
44489
+ card.appendChild(el("p", "", t2.intro.cardHow));
44490
+ const button = el("button", "gdp-btn gdp-btn-sm", t2.intro.cardButton);
44491
+ button.type = "button";
44492
+ button.addEventListener("click", () => {
44493
+ void addWorktree();
44494
+ });
44495
+ card.appendChild(button);
44496
+ return card;
44497
+ }
44498
+ function visibleFiles(item) {
44499
+ const hideTests = deps.getOptions().hideTests;
44500
+ return item.files.filter(
44501
+ (file) => matches(file.path, fileFilter) && !(hideTests && deps.isTestPath(file.path))
44502
+ );
44503
+ }
44504
+ function emptyTree() {
44505
+ return { dirs: /* @__PURE__ */ new Map(), files: [] };
44506
+ }
44507
+ function buildTree(files) {
44508
+ const root = emptyTree();
44509
+ for (const file of files) {
44510
+ const parts = file.path.split("/");
44511
+ let node = root;
44512
+ for (let i2 = 0; i2 < parts.length - 1; i2++) {
44513
+ const name = parts[i2];
44514
+ let child = node.dirs.get(name);
44515
+ if (!child) {
44516
+ child = emptyTree();
44517
+ node.dirs.set(name, child);
44518
+ }
44519
+ node = child;
44520
+ }
44521
+ node.files.push(file);
44522
+ }
44523
+ return root;
44524
+ }
44525
+ function collapseChain(name, node) {
44526
+ let label = name;
44527
+ let current = node;
44528
+ while (current.files.length === 0 && current.dirs.size === 1) {
44529
+ const [childName, child] = [...current.dirs.entries()][0];
44530
+ label = `${label}/${childName}`;
44531
+ current = child;
44532
+ }
44533
+ return [label, current];
44534
+ }
44535
+ function fileRow(item, file, depth, label) {
44536
+ const t2 = text3();
44537
+ const row = el("li", "tree-file");
44538
+ row.tabIndex = -1;
44539
+ row.dataset.path = file.path;
44540
+ row.dataset.key = fileKey(file);
44541
+ row.dataset.type = "blob";
44542
+ const currentRoute = route();
44543
+ if (currentRoute?.file === file.path && currentRoute.origin === file.origin) {
44544
+ row.classList.add("active");
44545
+ }
44546
+ row.style.setProperty("--lvl-pad", `${12 + depth * 14}px`);
44547
+ row.appendChild(el("span", "chev-spacer"));
44548
+ const badge = el("span", `badge ${file.status}`, file.status);
44549
+ badge.title = t2.files.statusTitles[file.status] || file.status;
44550
+ row.appendChild(badge);
44551
+ const name = el("span", "name", label);
44552
+ name.title = file.path;
44553
+ row.appendChild(name);
44554
+ const others = overlapOthers(item, file);
44555
+ if (others.length) {
44556
+ row.classList.add("worktree-overlap");
44557
+ const mark = el(
44558
+ "span",
44559
+ "stat worktree-overlap-count",
44560
+ String(others.length)
44561
+ );
44562
+ mark.title = t2.files.overlapTitle(others);
44563
+ row.appendChild(mark);
44564
+ name.title = `${file.path}
44565
+ ${t2.files.overlapTitle(others)}`;
44566
+ }
44567
+ return row;
44568
+ }
44569
+ function renderTreeInto(parent, item, node, depth) {
44570
+ for (const [rawName, rawChild] of node.dirs) {
44571
+ const [label, child] = collapseChain(rawName, rawChild);
44572
+ const li = el("li", "tree-dir");
44573
+ li.tabIndex = -1;
44574
+ li.dataset.type = "tree";
44575
+ li.style.setProperty("--lvl-pad", `${12 + depth * 14}px`);
44576
+ const chev = el("span", "chev");
44577
+ chev.innerHTML = chevronSvg();
44578
+ const icon = el("span", "dir-icon");
44579
+ icon.innerHTML = folderSvg(false);
44580
+ const name = el("span", "name", label);
44581
+ name.title = label;
44582
+ li.append(chev, icon, name);
44583
+ const toggle = (event) => {
44584
+ event.stopPropagation();
44585
+ const collapsed = li.classList.toggle("collapsed");
44586
+ icon.innerHTML = folderSvg(collapsed);
44587
+ };
44588
+ chev.addEventListener("click", toggle);
44589
+ icon.addEventListener("click", toggle);
44590
+ parent.appendChild(li);
44591
+ const children = el("ul", "tree-children");
44592
+ renderTreeInto(children, item, child, depth + 1);
44593
+ parent.appendChild(children);
44594
+ }
44595
+ for (const file of node.files) {
44596
+ const parts = file.path.split("/");
44597
+ parent.appendChild(
44598
+ fileRow(item, file, depth, parts[parts.length - 1] || file.path)
44599
+ );
44600
+ }
44601
+ }
44602
+ function renderFiles() {
44603
+ const t2 = text3();
44604
+ const list2 = document.getElementById("filelist");
44605
+ const title = document.querySelector(".sb-title");
44606
+ const totals = document.getElementById("totals");
44607
+ if (!list2) return;
44608
+ const tree = deps.getSidebarView() === "tree";
44609
+ list2.classList.toggle("tree", tree);
44610
+ for (const button of sidebarViewButtons()) {
44611
+ const active = button.dataset.view === (tree ? "tree" : "flat");
44612
+ button.classList.toggle("active", active);
44613
+ button.setAttribute("aria-pressed", String(active));
44614
+ }
44615
+ for (const button of document.querySelectorAll(
44616
+ ".sb-tree-action"
44617
+ )) {
44618
+ button.disabled = !tree;
44619
+ }
44620
+ if (title) title.textContent = t2.panes.files;
44621
+ const item = selectedWorktree();
44622
+ if (totals) {
44623
+ totals.textContent = item ? t2.files.heading(item.fileCount) : "";
44624
+ }
44625
+ list2.replaceChildren();
44626
+ if (!item) {
44627
+ list2.appendChild(note(t2.panes.selectWorktree));
44628
+ return;
44629
+ }
44630
+ if (!item.fileCount) {
44631
+ list2.appendChild(note(t2.files.none));
44632
+ return;
44633
+ }
44634
+ const shown = visibleFiles(item);
44635
+ if (!shown.length) {
44636
+ list2.appendChild(note(t2.panes.noFileMatch));
44637
+ return;
44638
+ }
44639
+ if (shown.some((entry) => overlapOthers(item, entry).length > 0)) {
44640
+ list2.appendChild(
44641
+ el("li", "worktree-overlap-legend", t2.intro.overlapLegend)
44642
+ );
44643
+ }
44644
+ for (const group of ["uncommitted", "committed"]) {
44645
+ const files = shown.filter((file) => file.origin === group);
44646
+ if (!files.length) continue;
44647
+ list2.appendChild(
44648
+ el(
44649
+ "li",
44650
+ "worktree-file-group",
44651
+ group === "uncommitted" ? t2.files.uncommitted : t2.files.committed
44652
+ )
44653
+ );
44654
+ if (tree) renderTreeInto(list2, item, buildTree(files), 0);
44655
+ else {
44656
+ for (const file of files) {
44657
+ list2.appendChild(fileRow(item, file, 0, file.path));
44658
+ }
44659
+ }
44660
+ }
44661
+ }
44662
+ function onFileListClick(event) {
44663
+ const row = event.target?.closest(
44664
+ ".tree-file"
44665
+ );
44666
+ const key = row?.dataset.key;
44667
+ if (!key) return;
44668
+ const shell = document.querySelector(
44669
+ `#diff .gdp-file-shell[data-key="${CSS.escape(key)}"]`
44670
+ );
44671
+ restoredRouteKey = key;
44672
+ shell?.scrollIntoView({ block: "start" });
44673
+ const [origin, ...rest] = key.split(":");
44674
+ navigate(
44675
+ {
44676
+ file: rest.join(":"),
44677
+ origin: origin === "committed" ? "committed" : "uncommitted"
44678
+ },
44679
+ true
44680
+ );
44681
+ }
44682
+ function diffKey(item) {
44683
+ const options = deps.getOptions();
44684
+ return [
44685
+ item?.path || "",
44686
+ options.layout,
44687
+ options.ignoreWs ? "w" : "",
44688
+ options.hideTests ? "t" : "",
44689
+ options.syntax ? "s" : "",
44690
+ fileFilter
44691
+ ].join("|");
44692
+ }
44693
+ async function loadShell(item, file, shell) {
44694
+ const seq = lifecycle;
44695
+ const renderKey = diffKey(item);
44696
+ const t2 = text3();
44697
+ const body = shell.querySelector(".gdp-shell-body");
44698
+ if (!body) return;
44699
+ const params = new URLSearchParams({
44700
+ path: item.path,
44701
+ file: file.path,
44702
+ origin: file.origin
44703
+ });
44704
+ if (file.status === "U") params.set("untracked", "1");
44705
+ if (deps.getOptions().ignoreWs) params.set("ignore_ws", "1");
44706
+ try {
44707
+ const res = await deps.trackLoad(
44708
+ fetch(`/_worktree/diff?${params.toString()}`).then(async (response) => {
44709
+ if (!response.ok) {
44710
+ throw new Error(await response.text() || `${response.status}`);
44711
+ }
44712
+ return await response.json();
44713
+ })
44714
+ );
44715
+ if (!isCurrent(seq) || !shell.isConnected || diffKey(item) !== renderKey) {
44716
+ return;
44717
+ }
44718
+ const options = deps.getOptions();
44719
+ const hljs = options.syntax ? await deps.loadHljs() : null;
44720
+ if (!isCurrent(seq) || !shell.isConnected || diffKey(item) !== renderKey) {
44721
+ return;
44722
+ }
44723
+ body.replaceChildren();
44724
+ if (!res.diff.trim()) {
44725
+ body.appendChild(el("div", "gdp-info", t2.panes.diffEmpty));
44726
+ } else {
44727
+ const head = shell.querySelector(".gdp-shell-header");
44728
+ if (head) head.style.display = "none";
44729
+ if (res.truncated) {
44730
+ body.appendChild(
44731
+ el(
44732
+ "div",
44733
+ "gdp-info",
44734
+ t2.panes.diffTruncated(res.renderedHunks, res.totalHunks)
44735
+ )
44736
+ );
44737
+ }
44738
+ const host = el("div", "");
44739
+ body.appendChild(host);
44740
+ const ui = new window.Diff2HtmlUI(
44741
+ host,
44742
+ res.diff,
44743
+ {
44744
+ drawFileList: false,
44745
+ matching: "lines",
44746
+ // topbar の 統合 / 分割。
44747
+ outputFormat: options.layout,
44748
+ synchronisedScroll: true,
44749
+ // topbar の「構文」。diff2html 自身に塗らせる (Diff ビューアは
44750
+ // 巨大ファイル対策で自前の idle 描画を持つが、こちらは 1 本ぶんの
44751
+ // 変更が対象なのでライブラリに任せる)。
44752
+ highlight: !!hljs,
44753
+ fileListToggle: false,
44754
+ fileContentToggle: false
44755
+ },
44756
+ hljs
44757
+ );
44758
+ ui.draw();
44759
+ }
44760
+ shell.classList.add("loaded");
44761
+ } catch (error2) {
44762
+ if (!isCurrent(seq) || !shell.isConnected) return;
44763
+ body.replaceChildren();
44764
+ const failure = el(
44765
+ "div",
44766
+ "gdp-info",
44767
+ error2 instanceof Error ? error2.message : t2.panes.diffFailed
44768
+ );
44769
+ failure.setAttribute("role", "alert");
44770
+ body.appendChild(failure);
44771
+ shell.classList.add("loaded");
44772
+ }
44773
+ }
44774
+ function renderDiffs() {
44775
+ const t2 = text3();
44776
+ const diff = document.getElementById("diff");
44777
+ if (!diff) return;
44778
+ const item = selectedWorktree();
44779
+ observer?.disconnect();
44780
+ observer = null;
44781
+ restoredRouteKey = null;
44782
+ diff.replaceChildren();
44783
+ if (!item) {
44784
+ if (data && data.worktrees.length === 1) {
44785
+ diff.appendChild(introCard());
44786
+ } else {
44787
+ diff.appendChild(el("div", "gdp-info", t2.panes.selectWorktree));
44788
+ }
44789
+ diffFor = "";
44790
+ return;
44791
+ }
44792
+ if (!item.fileCount) {
44793
+ const card = el("div", "gdp-info worktree-empty-diff");
44794
+ card.appendChild(el("p", "", t2.emptyDiff.title));
44795
+ card.appendChild(el("p", "", t2.emptyDiff.body(item.path)));
44796
+ if (!item.missing && !item.bare) {
44797
+ const buttons = el("span", "worktree-empty-diff-actions");
44798
+ const openFolder = openFolderButton(item, true);
44799
+ if (openFolder) buttons.appendChild(openFolder);
44800
+ buttons.appendChild(copyPathButton(item, true));
44801
+ card.appendChild(buttons);
44802
+ }
44803
+ diff.appendChild(card);
44804
+ diffFor = diffKey(item);
44805
+ return;
44806
+ }
44807
+ const files = visibleFiles(item);
44808
+ if (!files.length) {
44809
+ diff.appendChild(el("div", "gdp-info", t2.panes.noFileMatch));
44810
+ diffFor = diffKey(item);
44811
+ return;
44812
+ }
44813
+ const pending = /* @__PURE__ */ new Map();
44814
+ for (const file of files) {
44815
+ const shell = el("div", "gdp-file-shell");
44816
+ shell.dataset.path = file.path;
44817
+ shell.dataset.key = fileKey(file);
44818
+ shell.dataset.status = file.status;
44819
+ const head = el("div", "gdp-shell-header");
44820
+ head.appendChild(el("span", `status-pill ${file.status}`, file.status));
44821
+ head.appendChild(el("span", "path", file.path));
44822
+ const stats = el("span", "stats");
44823
+ stats.appendChild(el("span", "a", `+${file.additions}`));
44824
+ stats.appendChild(el("span", "d", `−${file.deletions}`));
44825
+ head.appendChild(stats);
44826
+ shell.appendChild(head);
44827
+ const body = el("div", "gdp-shell-body");
44828
+ body.appendChild(el("div", "gdp-info", t2.panes.diffLoading));
44829
+ shell.appendChild(body);
44830
+ diff.appendChild(shell);
44831
+ pending.set(shell, file);
44832
+ }
44833
+ diffFor = diffKey(item);
44834
+ if (typeof IntersectionObserver === "undefined") {
44835
+ for (const [shell, file] of pending) void loadShell(item, file, shell);
44836
+ return;
44837
+ }
44838
+ observer = new IntersectionObserver(
44839
+ (entries) => {
44840
+ for (const entry of entries) {
44841
+ if (!entry.isIntersecting) continue;
44842
+ const shell = entry.target;
44843
+ const file = pending.get(shell);
44844
+ if (!file) continue;
44845
+ pending.delete(shell);
44846
+ observer?.unobserve(shell);
44847
+ void loadShell(item, file, shell);
44848
+ }
44849
+ },
44850
+ { rootMargin: DIFF_PREFETCH_MARGIN }
44851
+ );
44852
+ for (const shell of pending.keys()) observer.observe(shell);
44853
+ }
44854
+ function render() {
44855
+ renderList();
44856
+ renderFiles();
44857
+ const item = selectedWorktree();
44858
+ if (diffKey(item) !== diffFor) renderDiffs();
44859
+ restoreRouteSelection();
44860
+ }
44861
+ function restoreRouteSelection() {
44862
+ const current = route();
44863
+ if (!current?.file || !current.origin) {
44864
+ restoredRouteKey = null;
44865
+ return;
44866
+ }
44867
+ const key = `${current.origin}:${current.file}`;
44868
+ if (key === restoredRouteKey) return;
44869
+ const shell = document.querySelector(
44870
+ `#diff .gdp-file-shell[data-key="${CSS.escape(key)}"]`
44871
+ );
44872
+ if (!shell) return;
44873
+ restoredRouteKey = key;
44874
+ shell.scrollIntoView({ block: "start" });
44875
+ }
44876
+ return {
44877
+ async enter() {
44878
+ if (deps.getRoute().screen !== "worktree") return;
44879
+ if (mounted) {
44880
+ render();
44881
+ return;
44882
+ }
44883
+ mount();
44884
+ await refresh();
44885
+ },
44886
+ suspend,
44887
+ reload() {
44888
+ if (!mounted) return this.enter();
44889
+ return refresh();
44890
+ },
44891
+ displayOptionsChanged() {
44892
+ if (!mounted) return;
44893
+ diffFor = null;
44894
+ render();
44895
+ },
44896
+ handleSse() {
44897
+ if (!mounted) return;
44898
+ if (sseTimer !== null) window.clearTimeout(sseTimer);
44899
+ sseTimer = window.setTimeout(() => {
44900
+ sseTimer = null;
44901
+ void refresh();
44902
+ }, SSE_REFRESH_DELAY_MS);
44903
+ },
44904
+ localize() {
44905
+ if (!mounted) return;
44906
+ diffFor = null;
44907
+ render();
44908
+ }
44909
+ };
44910
+ }
44911
+
43140
44912
  // web-src/app.ts
43141
44913
  window.GdpExpandLogic = GdpExpandLogic;
43142
44914
  (() => {
@@ -43310,12 +45082,12 @@ ${formatErrorDetail(error2)}`);
43310
45082
  }
43311
45083
  function setProjectBranch(branch) {
43312
45084
  PROJECT_BRANCH = branch;
43313
- const el = document.querySelector("#project-branch");
43314
- if (!el) return;
43315
- el.hidden = !branch;
43316
- const name = el.querySelector(".project-branch-name");
45085
+ const el2 = document.querySelector("#project-branch");
45086
+ if (!el2) return;
45087
+ el2.hidden = !branch;
45088
+ const name = el2.querySelector(".project-branch-name");
43317
45089
  if (name) name.textContent = branch;
43318
- el.title = branch ? `Current branch: ${branch}` : "";
45090
+ el2.title = branch ? `Current branch: ${branch}` : "";
43319
45091
  }
43320
45092
  function mergeLocalSettings(patch) {
43321
45093
  const next = { ...APP_SETTINGS };
@@ -44209,6 +45981,7 @@ ${error2.stack}` : ""}`
44209
45981
  history: "History",
44210
45982
  journal: "Work Log",
44211
45983
  database: "Datastores",
45984
+ worktree: "Worktrees",
44212
45985
  tools: "Tools",
44213
45986
  help: "Settings & Help"
44214
45987
  },
@@ -44544,6 +46317,7 @@ ${error2.stack}` : ""}`
44544
46317
  history: "履歴",
44545
46318
  journal: "ワークログ",
44546
46319
  database: "データストア",
46320
+ worktree: "作業ツリー",
44547
46321
  tools: "ツール",
44548
46322
  help: "設定・ヘルプ"
44549
46323
  },
@@ -44877,8 +46651,8 @@ ${error2.stack}` : ""}`
44877
46651
  return UI_TEXT[STATE.language];
44878
46652
  }
44879
46653
  function setElementText(selector, text3) {
44880
- const el = document.querySelector(selector);
44881
- if (el) el.textContent = text3;
46654
+ const el2 = document.querySelector(selector);
46655
+ if (el2) el2.textContent = text3;
44882
46656
  }
44883
46657
  function setButtonLabel(button, text3) {
44884
46658
  if (button) button.textContent = text3;
@@ -45064,6 +46838,7 @@ ${error2.stack}` : ""}`
45064
46838
  });
45065
46839
  relocalizeHistory?.();
45066
46840
  relocalizeJournal?.();
46841
+ relocalizeWorktree?.();
45067
46842
  relocalizeViewerSettings?.();
45068
46843
  SOURCE_VIEW.localize();
45069
46844
  setElementText(".annotation-panel-head strong", text3.annotations.title);
@@ -45097,6 +46872,7 @@ ${error2.stack}` : ""}`
45097
46872
  }
45098
46873
  let relocalizeHistory = null;
45099
46874
  let relocalizeJournal = null;
46875
+ let relocalizeWorktree = null;
45100
46876
  let relocalizeTools = null;
45101
46877
  let relocalizeViewerSettings = null;
45102
46878
  let relocalizeTerminal = null;
@@ -45125,14 +46901,14 @@ ${error2.stack}` : ""}`
45125
46901
  }
45126
46902
  }
45127
46903
  function setStatus(s2) {
45128
- const el = $("#status");
45129
- el.classList.remove("live", "refreshing", "error");
45130
- if (s2) el.classList.add(s2);
46904
+ const el2 = $("#status");
46905
+ el2.classList.remove("live", "refreshing", "error");
46906
+ if (s2) el2.classList.add(s2);
45131
46907
  const text3 = uiText();
45132
46908
  const label = s2 === "live" ? text3.global.statusLive : s2 === "refreshing" ? text3.global.statusLoading : s2 === "error" ? text3.global.statusError : text3.global.statusIdle;
45133
- const labelEl = el.querySelector(".status-label");
46909
+ const labelEl = el2.querySelector(".status-label");
45134
46910
  if (labelEl) labelEl.textContent = label;
45135
- el.setAttribute("aria-label", label);
46911
+ el2.setAttribute("aria-label", label);
45136
46912
  updateNetworkActivity();
45137
46913
  }
45138
46914
  function applyTheme() {
@@ -45196,7 +46972,8 @@ ${error2.stack}` : ""}`
45196
46972
  }
45197
46973
  function routeCanUseSyntaxHighlighter(route = STATE.route) {
45198
46974
  if (!STATE.syntaxHighlight) return false;
45199
- if (route.screen === "diff" || route.screen === "history") return true;
46975
+ if (route.screen === "diff" || route.screen === "history" || route.screen === "worktree")
46976
+ return true;
45200
46977
  return route.screen === "file" && sourceInternalPathKind(route.path) === null;
45201
46978
  }
45202
46979
  function ensureSyntaxHighlighterForRoute() {
@@ -45204,6 +46981,7 @@ ${error2.stack}` : ""}`
45204
46981
  loadSyntaxHighlighter().then((hljsRef) => {
45205
46982
  if (!hljsRef) return;
45206
46983
  rerenderLoadedDiffs();
46984
+ WORKTREE_VIEW?.displayOptionsChanged();
45207
46985
  });
45208
46986
  }
45209
46987
  function setLayout(layout, persist = true) {
@@ -45223,9 +47001,10 @@ ${error2.stack}` : ""}`
45223
47001
  }
45224
47002
  scheduleIdleHighlight(card, file);
45225
47003
  });
47004
+ WORKTREE_VIEW?.displayOptionsChanged();
45226
47005
  }
45227
- function setChevronIcon(el) {
45228
- el.innerHTML = '<svg class="octicon octicon-chevron-down" viewBox="0 0 12 12" width="12" height="12" fill="currentColor" aria-hidden="true"><path fill="currentColor" d="' + CHEVRON_DOWN_12_PATH + '"></path></svg>';
47006
+ function setChevronIcon(el2) {
47007
+ el2.innerHTML = '<svg class="octicon octicon-chevron-down" viewBox="0 0 12 12" width="12" height="12" fill="currentColor" aria-hidden="true"><path fill="currentColor" d="' + CHEVRON_DOWN_12_PATH + '"></path></svg>';
45229
47008
  }
45230
47009
  function scopeOmitSourceLabel() {
45231
47010
  return savedScopeOmitDirs() != null || savedScopeExcludeNames() != null ? uiText().settings.browserOverride : uiText().settings.serverDefault;
@@ -45506,6 +47285,7 @@ ${error2.stack}` : ""}`
45506
47285
  }
45507
47286
  let ANNOTATIONS_UI = null;
45508
47287
  let JOURNAL_VIEW = null;
47288
+ let WORKTREE_VIEW = null;
45509
47289
  function applyInlineAnnotations() {
45510
47290
  ANNOTATIONS_UI?.applyInlineAnnotations();
45511
47291
  }
@@ -45608,6 +47388,9 @@ ${error2.stack}` : ""}`
45608
47388
  if (previousRoute.screen === "journal" && nextRoute.screen !== "journal") {
45609
47389
  JOURNAL_VIEW?.suspend();
45610
47390
  }
47391
+ if (previousRoute.screen === "worktree" && nextRoute.screen !== "worktree") {
47392
+ WORKTREE_VIEW?.suspend();
47393
+ }
45611
47394
  STATE.route = nextRoute;
45612
47395
  STATE.from = nextRoute.range.from;
45613
47396
  STATE.to = nextRoute.range.to;
@@ -45634,13 +47417,19 @@ ${error2.stack}` : ""}`
45634
47417
  removeStandaloneSource();
45635
47418
  void JOURNAL_VIEW?.enter();
45636
47419
  }
47420
+ if (nextRoute.screen === "worktree") {
47421
+ cancelActiveSourceLoad("navigation");
47422
+ setPageMode();
47423
+ removeStandaloneSource();
47424
+ void WORKTREE_VIEW?.enter();
47425
+ }
45637
47426
  }
45638
- function setQueryHistoryPanelOpen(open) {
47427
+ function setQueryHistoryPanelOpen(open2) {
45639
47428
  const panel = document.getElementById("query-history-panel");
45640
47429
  if (!panel) return;
45641
- panel.hidden = !open;
45642
- document.body.classList.toggle("query-history-panel-open", open);
45643
- if (open && ANNOTATIONS_UI) {
47430
+ panel.hidden = !open2;
47431
+ document.body.classList.toggle("query-history-panel-open", open2);
47432
+ if (open2 && ANNOTATIONS_UI) {
45644
47433
  ANNOTATIONS_UI.setAnnotationPanelOpen(false);
45645
47434
  }
45646
47435
  }
@@ -45679,6 +47468,18 @@ ${error2.stack}` : ""}`
45679
47468
  "gdp-journal-page",
45680
47469
  STATE.route.screen === "journal"
45681
47470
  );
47471
+ document.body.classList.toggle(
47472
+ "gdp-worktree-page",
47473
+ STATE.route.screen === "worktree"
47474
+ );
47475
+ document.body.toggleAttribute(
47476
+ "data-content-scrolls-when-docked",
47477
+ STATE.route.screen === "diff" || STATE.route.screen === "history" || STATE.route.screen === "repo" || STATE.route.screen === "file" || STATE.route.screen === "help" || STATE.route.screen === "worktree"
47478
+ );
47479
+ document.body.toggleAttribute(
47480
+ "data-history-list-panel",
47481
+ historyPanelRoute || STATE.route.screen === "worktree"
47482
+ );
45682
47483
  const repoTargetWrap = document.querySelector("#repo-target-wrap");
45683
47484
  if (!repoSidebarRoute && repoTargetWrap) {
45684
47485
  repoTargetWrap.hidden = true;
@@ -45753,6 +47554,14 @@ ${error2.stack}` : ""}`
45753
47554
  })
45754
47555
  );
45755
47556
  }
47557
+ if (link2.dataset.route === "worktree") {
47558
+ link2.href = withOverlayState(
47559
+ buildRoute({
47560
+ screen: "worktree",
47561
+ range: currentRange()
47562
+ })
47563
+ );
47564
+ }
45756
47565
  if (link2.dataset.route === "help") {
45757
47566
  link2.href = withOverlayState(
45758
47567
  buildRoute({
@@ -45785,7 +47594,9 @@ ${error2.stack}` : ""}`
45785
47594
  setTimeout(() => {
45786
47595
  button?.classList.remove("opened");
45787
47596
  }, 1200);
45788
- } catch {
47597
+ return true;
47598
+ } catch (error2) {
47599
+ console.error("[code-viewer] failed to open path in OS", error2);
45789
47600
  if (button) {
45790
47601
  button.classList.add("failed");
45791
47602
  button.title = "failed to open in OS";
@@ -45794,6 +47605,7 @@ ${error2.stack}` : ""}`
45794
47605
  button.title = oldTitle || "open in OS";
45795
47606
  }, 1600);
45796
47607
  }
47608
+ return false;
45797
47609
  } finally {
45798
47610
  if (button) button.disabled = false;
45799
47611
  }
@@ -46316,10 +48128,7 @@ ${error2.stack}` : ""}`
46316
48128
  moveActiveSidebarItem(e2.key === "ArrowDown" ? 1 : -1);
46317
48129
  } else if (e2.key === "Escape") {
46318
48130
  if (sbFilter.value) {
46319
- sbFilter.value = "";
46320
- syncSidebarFilterClearButton();
46321
- flushSidebarFilter();
46322
- applyFilter();
48131
+ clearSidebarFilter();
46323
48132
  } else {
46324
48133
  sbFilter.blur();
46325
48134
  }
@@ -46767,6 +48576,9 @@ ${error2.stack}` : ""}`
46767
48576
  setStatus("live");
46768
48577
  return Promise.resolve(null);
46769
48578
  }
48579
+ if (STATE.route.screen === "worktree") {
48580
+ return (WORKTREE_VIEW?.reload() ?? Promise.resolve()).then(() => null);
48581
+ }
46770
48582
  if (STATE.route.screen === "file" && !(isFileHistoryRoute(STATE.route) && activeHistoryPathFilter) && // load() is by definition a reload (topbar Reload button, ignore-ws
46771
48583
  // toggle, catch-up after SSE reconnect) - bypass the idempotent-mount
46772
48584
  // guard so the blob view actually refetches, matching the pre-guard
@@ -46833,6 +48645,8 @@ ${error2.stack}` : ""}`
46833
48645
  } else if (STATE.route.screen === "journal") {
46834
48646
  setStatus("live");
46835
48647
  void JOURNAL_VIEW?.enter();
48648
+ } else if (STATE.route.screen === "worktree") {
48649
+ void WORKTREE_VIEW?.enter();
46836
48650
  } else load();
46837
48651
  syncLineRefPill();
46838
48652
  syncDoctorSheetFromUrl();
@@ -46975,9 +48789,9 @@ ${error2.stack}` : ""}`
46975
48789
  function isDoctorOverlayOpen() {
46976
48790
  return parseDoctorOverlay(window.location.pathname, window.location.search);
46977
48791
  }
46978
- function updateUrlForDoctorOverlay(open) {
48792
+ function updateUrlForDoctorOverlay(open2) {
46979
48793
  const current = window.location.pathname + window.location.search;
46980
- const next = withDoctorOverlay(current, open);
48794
+ const next = withDoctorOverlay(current, open2);
46981
48795
  if (next !== current) {
46982
48796
  history.replaceState(history.state, "", next + window.location.hash);
46983
48797
  }
@@ -46996,9 +48810,9 @@ ${error2.stack}` : ""}`
46996
48810
  }
46997
48811
  function syncDoctorSheetFromUrl() {
46998
48812
  const shouldOpen = isDoctorOverlayOpen();
46999
- const open = DOCTOR_VIEW.isOpen();
47000
- if (shouldOpen && !open) void DOCTOR_VIEW.open();
47001
- else if (!shouldOpen && open) DOCTOR_VIEW.close();
48813
+ const open2 = DOCTOR_VIEW.isOpen();
48814
+ if (shouldOpen && !open2) void DOCTOR_VIEW.open();
48815
+ else if (!shouldOpen && open2) DOCTOR_VIEW.close();
47002
48816
  }
47003
48817
  document.getElementById("doctor-sheet-overlay")?.addEventListener("click", () => closeDoctorSheet());
47004
48818
  document.addEventListener("keydown", (event) => {
@@ -47030,10 +48844,10 @@ ${error2.stack}` : ""}`
47030
48844
  function syncAppPanel() {
47031
48845
  const tools = parseToolsOverlay(window.location.search) !== null;
47032
48846
  const terminal = parseTerminalOverlay(window.location.search) !== null;
47033
- const open = tools || terminal;
48847
+ const open2 = tools || terminal;
47034
48848
  const panel = document.getElementById("app-panel");
47035
48849
  if (panel) {
47036
- panel.classList.toggle("app-panel-open", open);
48850
+ panel.classList.toggle("app-panel-open", open2);
47037
48851
  }
47038
48852
  for (const [id, selected] of [
47039
48853
  ["#panel-tab-tools", tools],
@@ -47121,10 +48935,10 @@ ${error2.stack}` : ""}`
47121
48935
  }
47122
48936
  function syncToolsSheetFromUrl() {
47123
48937
  const tool = openToolsOverlay();
47124
- const open = TOOLS_VIEW.isOpen();
47125
- if (tool && (!open || TOOLS_VIEW.getActiveTool() !== tool))
48938
+ const open2 = TOOLS_VIEW.isOpen();
48939
+ if (tool && (!open2 || TOOLS_VIEW.getActiveTool() !== tool))
47126
48940
  void TOOLS_VIEW.open(tool);
47127
- else if (!tool && open) TOOLS_VIEW.close();
48941
+ else if (!tool && open2) TOOLS_VIEW.close();
47128
48942
  syncAppPanel();
47129
48943
  }
47130
48944
  const TERMINAL_VIEW = createTerminalView({
@@ -47167,11 +48981,11 @@ ${error2.stack}` : ""}`
47167
48981
  }
47168
48982
  function syncTerminalSheetFromUrl() {
47169
48983
  const state = parseTerminalOverlay(window.location.search);
47170
- const open = TERMINAL_VIEW.isOpen();
48984
+ const open2 = TERMINAL_VIEW.isOpen();
47171
48985
  const target = state === "open" ? null : state;
47172
- if (state && (!open || target && TERMINAL_VIEW.getActiveTarget() !== target)) {
48986
+ if (state && (!open2 || target && TERMINAL_VIEW.getActiveTarget() !== target)) {
47173
48987
  void TERMINAL_VIEW.open(target);
47174
- } else if (!state && open) {
48988
+ } else if (!state && open2) {
47175
48989
  TERMINAL_VIEW.close();
47176
48990
  }
47177
48991
  syncAppPanel();
@@ -47187,6 +49001,30 @@ ${error2.stack}` : ""}`
47187
49001
  setStatus
47188
49002
  });
47189
49003
  relocalizeJournal = () => JOURNAL_VIEW?.localize();
49004
+ WORKTREE_VIEW = createWorktreeView({
49005
+ getRoute: () => STATE.route,
49006
+ // topbar のトグルは Diff ビューアと同じものを使う。値の出所も同じ STATE。
49007
+ getOptions: () => ({
49008
+ layout: STATE.layout,
49009
+ ignoreWs: STATE.ignoreWs,
49010
+ hideTests: STATE.hideTests,
49011
+ syntax: STATE.syntaxHighlight
49012
+ }),
49013
+ isTestPath: isTestFilePath,
49014
+ getSidebarView: () => STATE.sbView,
49015
+ // ハイライタは遅延バンドル。差分を描く直前に読み込ませる。
49016
+ loadHljs: loadSyntaxHighlighter,
49017
+ setRoute,
49018
+ currentRange,
49019
+ trackLoad,
49020
+ getText: () => worktreeText(STATE.language),
49021
+ setPageMode,
49022
+ syncHeaderMenu,
49023
+ setStatus,
49024
+ createOpenPathButton,
49025
+ openPathInOs: (path, kind) => openPathInOs(path, kind)
49026
+ });
49027
+ relocalizeWorktree = () => WORKTREE_VIEW?.localize();
47190
49028
  const DATABASE_VIEW = createDatabaseView({
47191
49029
  setRoute,
47192
49030
  setPageMode,
@@ -47245,6 +49083,8 @@ ${error2.stack}` : ""}`
47245
49083
  DATABASE_VIEW.suspend();
47246
49084
  if (previousRoute.screen === "journal" && nextRoute.screen !== "journal")
47247
49085
  JOURNAL_VIEW?.suspend();
49086
+ if (previousRoute.screen === "worktree" && nextRoute.screen !== "worktree")
49087
+ WORKTREE_VIEW?.suspend();
47248
49088
  if (isHistoryPanelRoute(previousRoute) && !isHistoryPanelRoute(nextRoute))
47249
49089
  HISTORY_VIEW.leaveHistory();
47250
49090
  if (isHistoryPanelRoute(previousRoute) && !isHistoryPanelRoute(nextRoute))
@@ -47314,6 +49154,13 @@ ${error2.stack}` : ""}`
47314
49154
  setStatus("live");
47315
49155
  return;
47316
49156
  }
49157
+ if (STATE.route.screen === "worktree") {
49158
+ cancelActiveSourceLoad("navigation");
49159
+ setPageMode();
49160
+ removeStandaloneSource();
49161
+ void WORKTREE_VIEW?.enter();
49162
+ return;
49163
+ }
47317
49164
  if (STATE.route.screen !== "file") {
47318
49165
  cancelActiveSourceLoad("navigation");
47319
49166
  setPageMode();
@@ -47365,6 +49212,7 @@ ${error2.stack}` : ""}`
47365
49212
  ensureSyntaxHighlighterForRoute();
47366
49213
  } else {
47367
49214
  rerenderLoadedDiffs();
49215
+ WORKTREE_VIEW?.displayOptionsChanged();
47368
49216
  }
47369
49217
  }
47370
49218
  setHighlightButton(STATE.syntaxHighlight && getHljs() ? "loaded" : "idle");
@@ -47389,6 +49237,7 @@ ${error2.stack}` : ""}`
47389
49237
  else updateTreeDirVisibility();
47390
49238
  if (typeof applyViewedState === "function") applyViewedState();
47391
49239
  applyHideTestsToMeta();
49240
+ WORKTREE_VIEW?.displayOptionsChanged();
47392
49241
  }
47393
49242
  function visibleDiffMetaForBrief(meta) {
47394
49243
  if (!meta.totals) return meta;
@@ -47441,7 +49290,7 @@ ${error2.stack}` : ""}`
47441
49290
  getFiles: () => STATE.files,
47442
49291
  getRoute: () => STATE.route,
47443
49292
  getAnnotationPanelOpen: () => APP_SETTINGS.annotationPanelOpen === true,
47444
- setAnnotationPanelOpenState: (open) => patchSettings({ annotationPanelOpen: open }),
49293
+ setAnnotationPanelOpenState: (open2) => patchSettings({ annotationPanelOpen: open2 }),
47445
49294
  getAnnotationPanelWidth: () => APP_SETTINGS.annotationPanelWidth,
47446
49295
  setAnnotationPanelWidth: (width) => patchSettings({ annotationPanelWidth: width }),
47447
49296
  getAnnotationFollow: () => APP_SETTINGS.annotationFollow !== false,
@@ -47502,7 +49351,7 @@ ${error2.stack}` : ""}`
47502
49351
  $,
47503
49352
  getActiveSessionEntries: () => ANNOTATIONS_UI?.getActiveSessionEntries() ?? [],
47504
49353
  openAnnotationEntry: (id) => ANNOTATIONS_UI ? ANNOTATIONS_UI.openAnnotationEntry(id) : Promise.resolve(),
47505
- setAnnotationPanelOpen: (open) => ANNOTATIONS_UI?.setAnnotationPanelOpen(open),
49354
+ setAnnotationPanelOpen: (open2) => ANNOTATIONS_UI?.setAnnotationPanelOpen(open2),
47506
49355
  onAnnotationsChanged: (cb) => ANNOTATIONS_UI?.onAnnotationsChanged(cb),
47507
49356
  onAnnotationOpened: (cb) => ANNOTATIONS_UI?.onAnnotationOpened(cb),
47508
49357
  getActiveAnnotationId: () => ANNOTATIONS_UI ? ANNOTATIONS_UI.getActiveAnnotationId() : null,
@@ -47745,6 +49594,7 @@ ${error2.stack}` : ""}`
47745
49594
  }
47746
49595
  }
47747
49596
  if (isHistoryPanelRoute(STATE.route)) HISTORY_VIEW.notePossibleUpdate();
49597
+ if (STATE.route.screen === "worktree") WORKTREE_VIEW?.handleSse();
47748
49598
  scheduleSseLoad(paths);
47749
49599
  });
47750
49600
  es.addEventListener("watch-limit", (event) => {