@achasoft/dsh-advanced-sidebar 0.1.0 → 0.3.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.
Files changed (38) hide show
  1. package/README.md +279 -128
  2. package/cordis.patch.yml +31 -3
  3. package/lib/client.js +2803 -466
  4. package/lib/client.js.map +1 -1
  5. package/lib/host.js +2071 -418
  6. package/lib/index.js +6 -2
  7. package/lib/preview-content-BVUQ5oOR.js +465 -0
  8. package/lib/remote.js +330 -25
  9. package/lib/typert.host.js +330 -25
  10. package/lib/ui-preview.js +352 -0
  11. package/package.json +8 -2
  12. package/types/client/ActionMenu.d.ts +16 -1
  13. package/types/client/LogDownloadDialog.d.ts +24 -0
  14. package/types/client/contract.d.ts +57 -1
  15. package/types/client/index.d.ts +4 -2
  16. package/types/client/locales.d.ts +100 -0
  17. package/types/client/log-download.d.ts +179 -0
  18. package/types/client/panels/PreviewPanel.d.ts +20 -15
  19. package/types/client/panels/preview-file.d.ts +61 -0
  20. package/types/client/panels/preview-mode.d.ts +67 -0
  21. package/types/client/panels/preview-scratchpad.d.ts +53 -0
  22. package/types/client/panels/preview-url.d.ts +17 -0
  23. package/types/client/panels/shared.d.ts +15 -2
  24. package/types/client/preview-driver.d.ts +121 -0
  25. package/types/client/preview-storage.d.ts +43 -0
  26. package/types/client/preview-types.d.ts +21 -0
  27. package/types/client/preview-values.d.ts +43 -0
  28. package/types/host/deletion.d.ts +32 -23
  29. package/types/host/git.d.ts +94 -8
  30. package/types/host/index.d.ts +97 -5
  31. package/types/host/preview-content.d.ts +179 -0
  32. package/types/host/preview-serve.d.ts +242 -0
  33. package/types/host/settings-section.d.ts +49 -0
  34. package/types/host/types.d.ts +341 -0
  35. package/types/host/ui-bridge.d.ts +197 -0
  36. package/types/host/ui-preview-tool.d.ts +60 -0
  37. package/types/index.d.ts +6 -2
  38. package/types/ui-preview.d.ts +11 -0
package/lib/client.js CHANGED
@@ -115,8 +115,8 @@ function cached(getter) {
115
115
  throw new Error("cached value already set");
116
116
  } };
117
117
  }
118
- function nullish(input) {
119
- return input === null || input === void 0;
118
+ function nullish(input$1) {
119
+ return input$1 === null || input$1 === void 0;
120
120
  }
121
121
  function cleanRegex(source) {
122
122
  const start = source.startsWith("^") ? 1 : 0;
@@ -167,8 +167,8 @@ function mergeDefs(...defs) {
167
167
  function esc(str) {
168
168
  return JSON.stringify(str);
169
169
  }
170
- function slugify(input) {
171
- return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
170
+ function slugify(input$1) {
171
+ return input$1.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
172
172
  }
173
173
  const captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {};
174
174
  function isObject(data) {
@@ -395,17 +395,17 @@ function finalizeIssue(iss, ctx, config$1) {
395
395
  if (ctx?.reportInput) rest.input = _input;
396
396
  return rest;
397
397
  }
398
- function getLengthableOrigin(input) {
399
- if (Array.isArray(input)) return "array";
400
- if (typeof input === "string") return "string";
398
+ function getLengthableOrigin(input$1) {
399
+ if (Array.isArray(input$1)) return "array";
400
+ if (typeof input$1 === "string") return "string";
401
401
  return "unknown";
402
402
  }
403
403
  function issue(...args) {
404
- const [iss, input, inst] = args;
404
+ const [iss, input$1, inst] = args;
405
405
  if (typeof iss === "string") return {
406
406
  message: iss,
407
407
  code: "custom",
408
- input,
408
+ input: input$1,
409
409
  inst
410
410
  };
411
411
  return { ...iss };
@@ -753,22 +753,22 @@ const $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberForma
753
753
  if (isInt) bag.pattern = integer;
754
754
  });
755
755
  inst._zod.check = (payload) => {
756
- const input = payload.value;
756
+ const input$1 = payload.value;
757
757
  if (isInt) {
758
- if (!Number.isInteger(input)) {
758
+ if (!Number.isInteger(input$1)) {
759
759
  payload.issues.push({
760
760
  expected: origin,
761
761
  format: def.format,
762
762
  code: "invalid_type",
763
763
  continue: false,
764
- input,
764
+ input: input$1,
765
765
  inst
766
766
  });
767
767
  return;
768
768
  }
769
- if (!Number.isSafeInteger(input)) {
770
- if (input > 0) payload.issues.push({
771
- input,
769
+ if (!Number.isSafeInteger(input$1)) {
770
+ if (input$1 > 0) payload.issues.push({
771
+ input: input$1,
772
772
  code: "too_big",
773
773
  maximum: Number.MAX_SAFE_INTEGER,
774
774
  note: "Integers must be within the safe integer range.",
@@ -778,7 +778,7 @@ const $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberForma
778
778
  continue: !def.abort
779
779
  });
780
780
  else payload.issues.push({
781
- input,
781
+ input: input$1,
782
782
  code: "too_small",
783
783
  minimum: Number.MIN_SAFE_INTEGER,
784
784
  note: "Integers must be within the safe integer range.",
@@ -790,18 +790,18 @@ const $ZodCheckNumberFormat = /* @__PURE__ */ $constructor("$ZodCheckNumberForma
790
790
  return;
791
791
  }
792
792
  }
793
- if (input < minimum) payload.issues.push({
793
+ if (input$1 < minimum) payload.issues.push({
794
794
  origin: "number",
795
- input,
795
+ input: input$1,
796
796
  code: "too_small",
797
797
  minimum,
798
798
  inclusive: true,
799
799
  inst,
800
800
  continue: !def.abort
801
801
  });
802
- if (input > maximum) payload.issues.push({
802
+ if (input$1 > maximum) payload.issues.push({
803
803
  origin: "number",
804
- input,
804
+ input: input$1,
805
805
  code: "too_big",
806
806
  maximum,
807
807
  inclusive: true,
@@ -822,15 +822,15 @@ const $ZodCheckMaxLength = /* @__PURE__ */ $constructor("$ZodCheckMaxLength", (i
822
822
  if (def.maximum < curr) inst$1._zod.bag.maximum = def.maximum;
823
823
  });
824
824
  inst._zod.check = (payload) => {
825
- const input = payload.value;
826
- if (input.length <= def.maximum) return;
827
- const origin = getLengthableOrigin(input);
825
+ const input$1 = payload.value;
826
+ if (input$1.length <= def.maximum) return;
827
+ const origin = getLengthableOrigin(input$1);
828
828
  payload.issues.push({
829
829
  origin,
830
830
  code: "too_big",
831
831
  maximum: def.maximum,
832
832
  inclusive: true,
833
- input,
833
+ input: input$1,
834
834
  inst,
835
835
  continue: !def.abort
836
836
  });
@@ -848,15 +848,15 @@ const $ZodCheckMinLength = /* @__PURE__ */ $constructor("$ZodCheckMinLength", (i
848
848
  if (def.minimum > curr) inst$1._zod.bag.minimum = def.minimum;
849
849
  });
850
850
  inst._zod.check = (payload) => {
851
- const input = payload.value;
852
- if (input.length >= def.minimum) return;
853
- const origin = getLengthableOrigin(input);
851
+ const input$1 = payload.value;
852
+ if (input$1.length >= def.minimum) return;
853
+ const origin = getLengthableOrigin(input$1);
854
854
  payload.issues.push({
855
855
  origin,
856
856
  code: "too_small",
857
857
  minimum: def.minimum,
858
858
  inclusive: true,
859
- input,
859
+ input: input$1,
860
860
  inst,
861
861
  continue: !def.abort
862
862
  });
@@ -876,10 +876,10 @@ const $ZodCheckLengthEquals = /* @__PURE__ */ $constructor("$ZodCheckLengthEqual
876
876
  bag.length = def.length;
877
877
  });
878
878
  inst._zod.check = (payload) => {
879
- const input = payload.value;
880
- const length = input.length;
879
+ const input$1 = payload.value;
880
+ const length = input$1.length;
881
881
  if (length === def.length) return;
882
- const origin = getLengthableOrigin(input);
882
+ const origin = getLengthableOrigin(input$1);
883
883
  const tooBig = length > def.length;
884
884
  payload.issues.push({
885
885
  origin,
@@ -1441,13 +1441,13 @@ const $ZodNumber = /* @__PURE__ */ $constructor("$ZodNumber", (inst, def) => {
1441
1441
  if (def.coerce) try {
1442
1442
  payload.value = Number(payload.value);
1443
1443
  } catch (_) {}
1444
- const input = payload.value;
1445
- if (typeof input === "number" && !Number.isNaN(input) && Number.isFinite(input)) return payload;
1446
- const received = typeof input === "number" ? Number.isNaN(input) ? "NaN" : !Number.isFinite(input) ? "Infinity" : void 0 : void 0;
1444
+ const input$1 = payload.value;
1445
+ if (typeof input$1 === "number" && !Number.isNaN(input$1) && Number.isFinite(input$1)) return payload;
1446
+ const received = typeof input$1 === "number" ? Number.isNaN(input$1) ? "NaN" : !Number.isFinite(input$1) ? "Infinity" : void 0 : void 0;
1447
1447
  payload.issues.push({
1448
1448
  expected: "number",
1449
1449
  code: "invalid_type",
1450
- input,
1450
+ input: input$1,
1451
1451
  inst,
1452
1452
  ...received ? { received } : {}
1453
1453
  });
@@ -1465,12 +1465,12 @@ const $ZodBoolean = /* @__PURE__ */ $constructor("$ZodBoolean", (inst, def) => {
1465
1465
  if (def.coerce) try {
1466
1466
  payload.value = Boolean(payload.value);
1467
1467
  } catch (_) {}
1468
- const input = payload.value;
1469
- if (typeof input === "boolean") return payload;
1468
+ const input$1 = payload.value;
1469
+ if (typeof input$1 === "boolean") return payload;
1470
1470
  payload.issues.push({
1471
1471
  expected: "boolean",
1472
1472
  code: "invalid_type",
1473
- input,
1473
+ input: input$1,
1474
1474
  inst
1475
1475
  });
1476
1476
  return payload;
@@ -1481,12 +1481,12 @@ const $ZodNull = /* @__PURE__ */ $constructor("$ZodNull", (inst, def) => {
1481
1481
  inst._zod.pattern = _null$2;
1482
1482
  inst._zod.values = new Set([null]);
1483
1483
  inst._zod.parse = (payload, _ctx) => {
1484
- const input = payload.value;
1485
- if (input === null) return payload;
1484
+ const input$1 = payload.value;
1485
+ if (input$1 === null) return payload;
1486
1486
  payload.issues.push({
1487
1487
  expected: "null",
1488
1488
  code: "invalid_type",
1489
- input,
1489
+ input: input$1,
1490
1490
  inst
1491
1491
  });
1492
1492
  return payload;
@@ -1515,20 +1515,20 @@ function handleArrayResult(result, final, index) {
1515
1515
  const $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
1516
1516
  $ZodType.init(inst, def);
1517
1517
  inst._zod.parse = (payload, ctx) => {
1518
- const input = payload.value;
1519
- if (!Array.isArray(input)) {
1518
+ const input$1 = payload.value;
1519
+ if (!Array.isArray(input$1)) {
1520
1520
  payload.issues.push({
1521
1521
  expected: "array",
1522
1522
  code: "invalid_type",
1523
- input,
1523
+ input: input$1,
1524
1524
  inst
1525
1525
  });
1526
1526
  return payload;
1527
1527
  }
1528
- payload.value = Array(input.length);
1528
+ payload.value = Array(input$1.length);
1529
1529
  const proms = [];
1530
- for (let i = 0; i < input.length; i++) {
1531
- const item = input[i];
1530
+ for (let i = 0; i < input$1.length; i++) {
1531
+ const item = input$1[i];
1532
1532
  const result = def.element._zod.run({
1533
1533
  value: item,
1534
1534
  issues: []
@@ -1540,8 +1540,8 @@ const $ZodArray = /* @__PURE__ */ $constructor("$ZodArray", (inst, def) => {
1540
1540
  return payload;
1541
1541
  };
1542
1542
  });
1543
- function handlePropertyResult(result, final, key, input, isOptionalIn, isOptionalOut) {
1544
- const isPresent = key in input;
1543
+ function handlePropertyResult(result, final, key, input$1, isOptionalIn, isOptionalOut) {
1544
+ const isPresent = key in input$1;
1545
1545
  if (result.issues.length) {
1546
1546
  if (isOptionalIn && isOptionalOut && !isPresent) return;
1547
1547
  final.issues.push(...prefixIssues(key, result.issues));
@@ -1571,14 +1571,14 @@ function normalizeDef(def) {
1571
1571
  optionalKeys: new Set(okeys)
1572
1572
  };
1573
1573
  }
1574
- function handleCatchall(proms, input, payload, ctx, def, inst) {
1574
+ function handleCatchall(proms, input$1, payload, ctx, def, inst) {
1575
1575
  const unrecognized = [];
1576
1576
  const keySet = def.keySet;
1577
1577
  const _catchall = def.catchall._zod;
1578
1578
  const t = _catchall.def.type;
1579
1579
  const isOptionalIn = _catchall.optin === "optional";
1580
1580
  const isOptionalOut = _catchall.optout === "optional";
1581
- for (const key in input) {
1581
+ for (const key in input$1) {
1582
1582
  if (key === "__proto__") continue;
1583
1583
  if (keySet.has(key)) continue;
1584
1584
  if (t === "never") {
@@ -1586,16 +1586,16 @@ function handleCatchall(proms, input, payload, ctx, def, inst) {
1586
1586
  continue;
1587
1587
  }
1588
1588
  const r = _catchall.run({
1589
- value: input[key],
1589
+ value: input$1[key],
1590
1590
  issues: []
1591
1591
  }, ctx);
1592
- if (r instanceof Promise) proms.push(r.then((r$1) => handlePropertyResult(r$1, payload, key, input, isOptionalIn, isOptionalOut)));
1593
- else handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut);
1592
+ if (r instanceof Promise) proms.push(r.then((r$1) => handlePropertyResult(r$1, payload, key, input$1, isOptionalIn, isOptionalOut)));
1593
+ else handlePropertyResult(r, payload, key, input$1, isOptionalIn, isOptionalOut);
1594
1594
  }
1595
1595
  if (unrecognized.length) payload.issues.push({
1596
1596
  code: "unrecognized_keys",
1597
1597
  keys: unrecognized,
1598
- input,
1598
+ input: input$1,
1599
1599
  inst
1600
1600
  });
1601
1601
  if (!proms.length) return payload;
@@ -1631,12 +1631,12 @@ const $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
1631
1631
  let value;
1632
1632
  inst._zod.parse = (payload, ctx) => {
1633
1633
  value ?? (value = _normalized.value);
1634
- const input = payload.value;
1635
- if (!isObject$1(input)) {
1634
+ const input$1 = payload.value;
1635
+ if (!isObject$1(input$1)) {
1636
1636
  payload.issues.push({
1637
1637
  expected: "object",
1638
1638
  code: "invalid_type",
1639
- input,
1639
+ input: input$1,
1640
1640
  inst
1641
1641
  });
1642
1642
  return payload;
@@ -1649,14 +1649,14 @@ const $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
1649
1649
  const isOptionalIn = el._zod.optin === "optional";
1650
1650
  const isOptionalOut = el._zod.optout === "optional";
1651
1651
  const r = el._zod.run({
1652
- value: input[key],
1652
+ value: input$1[key],
1653
1653
  issues: []
1654
1654
  }, ctx);
1655
- if (r instanceof Promise) proms.push(r.then((r$1) => handlePropertyResult(r$1, payload, key, input, isOptionalIn, isOptionalOut)));
1656
- else handlePropertyResult(r, payload, key, input, isOptionalIn, isOptionalOut);
1655
+ if (r instanceof Promise) proms.push(r.then((r$1) => handlePropertyResult(r$1, payload, key, input$1, isOptionalIn, isOptionalOut)));
1656
+ else handlePropertyResult(r, payload, key, input$1, isOptionalIn, isOptionalOut);
1657
1657
  }
1658
1658
  if (!catchall) return proms.length ? Promise.all(proms).then(() => payload) : payload;
1659
- return handleCatchall(proms, input, payload, ctx, _normalized.value, inst);
1659
+ return handleCatchall(proms, input$1, payload, ctx, _normalized.value, inst);
1660
1660
  };
1661
1661
  });
1662
1662
  const $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) => {
@@ -1763,12 +1763,12 @@ const $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def)
1763
1763
  let value;
1764
1764
  inst._zod.parse = (payload, ctx) => {
1765
1765
  value ?? (value = _normalized.value);
1766
- const input = payload.value;
1767
- if (!isObject$1(input)) {
1766
+ const input$1 = payload.value;
1767
+ if (!isObject$1(input$1)) {
1768
1768
  payload.issues.push({
1769
1769
  expected: "object",
1770
1770
  code: "invalid_type",
1771
- input,
1771
+ input: input$1,
1772
1772
  inst
1773
1773
  });
1774
1774
  return payload;
@@ -1777,7 +1777,7 @@ const $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def)
1777
1777
  if (!fastpass) fastpass = generateFastpass(def.shape);
1778
1778
  payload = fastpass(payload, ctx);
1779
1779
  if (!catchall) return payload;
1780
- return handleCatchall([], input, payload, ctx, value, inst);
1780
+ return handleCatchall([], input$1, payload, ctx, value, inst);
1781
1781
  }
1782
1782
  return superParse(payload, ctx);
1783
1783
  };
@@ -1840,13 +1840,13 @@ const $ZodUnion = /* @__PURE__ */ $constructor("$ZodUnion", (inst, def) => {
1840
1840
  const $ZodIntersection = /* @__PURE__ */ $constructor("$ZodIntersection", (inst, def) => {
1841
1841
  $ZodType.init(inst, def);
1842
1842
  inst._zod.parse = (payload, ctx) => {
1843
- const input = payload.value;
1843
+ const input$1 = payload.value;
1844
1844
  const left = def.left._zod.run({
1845
- value: input,
1845
+ value: input$1,
1846
1846
  issues: []
1847
1847
  }, ctx);
1848
1848
  const right = def.right._zod.run({
1849
- value: input,
1849
+ value: input$1,
1850
1850
  issues: []
1851
1851
  }, ctx);
1852
1852
  if (left instanceof Promise || right instanceof Promise) return Promise.all([left, right]).then(([left$1, right$1]) => {
@@ -1943,12 +1943,12 @@ const $ZodEnum = /* @__PURE__ */ $constructor("$ZodEnum", (inst, def) => {
1943
1943
  inst._zod.values = valuesSet;
1944
1944
  inst._zod.pattern = /* @__PURE__ */ new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex(o) : o.toString()).join("|")})$`);
1945
1945
  inst._zod.parse = (payload, _ctx) => {
1946
- const input = payload.value;
1947
- if (valuesSet.has(input)) return payload;
1946
+ const input$1 = payload.value;
1947
+ if (valuesSet.has(input$1)) return payload;
1948
1948
  payload.issues.push({
1949
1949
  code: "invalid_value",
1950
1950
  values,
1951
- input,
1951
+ input: input$1,
1952
1952
  inst
1953
1953
  });
1954
1954
  return payload;
@@ -1961,12 +1961,12 @@ const $ZodLiteral = /* @__PURE__ */ $constructor("$ZodLiteral", (inst, def) => {
1961
1961
  inst._zod.values = values;
1962
1962
  inst._zod.pattern = /* @__PURE__ */ new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex(o) : o ? escapeRegex(o.toString()) : String(o)).join("|")})$`);
1963
1963
  inst._zod.parse = (payload, _ctx) => {
1964
- const input = payload.value;
1965
- if (values.has(input)) return payload;
1964
+ const input$1 = payload.value;
1965
+ if (values.has(input$1)) return payload;
1966
1966
  payload.issues.push({
1967
1967
  code: "invalid_value",
1968
1968
  values: def.values,
1969
- input,
1969
+ input: input$1,
1970
1970
  inst
1971
1971
  });
1972
1972
  return payload;
@@ -1989,8 +1989,8 @@ const $ZodTransform = /* @__PURE__ */ $constructor("$ZodTransform", (inst, def)
1989
1989
  return payload;
1990
1990
  };
1991
1991
  });
1992
- function handleOptionalResult(result, input) {
1993
- if (input === void 0 && (result.issues.length || result.fallback)) return {
1992
+ function handleOptionalResult(result, input$1) {
1993
+ if (input$1 === void 0 && (result.issues.length || result.fallback)) return {
1994
1994
  issues: [],
1995
1995
  value: void 0
1996
1996
  };
@@ -2009,10 +2009,10 @@ const $ZodOptional = /* @__PURE__ */ $constructor("$ZodOptional", (inst, def) =>
2009
2009
  });
2010
2010
  inst._zod.parse = (payload, ctx) => {
2011
2011
  if (def.innerType._zod.optin === "optional") {
2012
- const input = payload.value;
2012
+ const input$1 = payload.value;
2013
2013
  const result = def.innerType._zod.run(payload, ctx);
2014
- if (result instanceof Promise) return result.then((r) => handleOptionalResult(r, input));
2015
- return handleOptionalResult(result, input);
2014
+ if (result instanceof Promise) return result.then((r) => handleOptionalResult(r, input$1));
2015
+ return handleOptionalResult(result, input$1);
2016
2016
  }
2017
2017
  if (payload.value === void 0) return payload;
2018
2018
  return def.innerType._zod.run(payload, ctx);
@@ -2181,17 +2181,17 @@ const $ZodCustom = /* @__PURE__ */ $constructor("$ZodCustom", (inst, def) => {
2181
2181
  return payload;
2182
2182
  };
2183
2183
  inst._zod.check = (payload) => {
2184
- const input = payload.value;
2185
- const r = def.fn(input);
2186
- if (r instanceof Promise) return r.then((r$1) => handleRefineResult(r$1, payload, input, inst));
2187
- handleRefineResult(r, payload, input, inst);
2184
+ const input$1 = payload.value;
2185
+ const r = def.fn(input$1);
2186
+ if (r instanceof Promise) return r.then((r$1) => handleRefineResult(r$1, payload, input$1, inst));
2187
+ handleRefineResult(r, payload, input$1, inst);
2188
2188
  };
2189
2189
  });
2190
- function handleRefineResult(result, payload, input, inst) {
2190
+ function handleRefineResult(result, payload, input$1, inst) {
2191
2191
  if (!result) {
2192
2192
  const _iss = {
2193
2193
  code: "custom",
2194
- input,
2194
+ input: input$1,
2195
2195
  inst,
2196
2196
  path: [...inst._zod.def.path ?? []],
2197
2197
  continue: !inst._zod.def.abort
@@ -2700,23 +2700,23 @@ function _overwrite(tx) {
2700
2700
  }
2701
2701
  /* @__NO_SIDE_EFFECTS__ */
2702
2702
  function _normalize(form) {
2703
- return /* @__PURE__ */ _overwrite((input) => input.normalize(form));
2703
+ return /* @__PURE__ */ _overwrite((input$1) => input$1.normalize(form));
2704
2704
  }
2705
2705
  /* @__NO_SIDE_EFFECTS__ */
2706
2706
  function _trim() {
2707
- return /* @__PURE__ */ _overwrite((input) => input.trim());
2707
+ return /* @__PURE__ */ _overwrite((input$1) => input$1.trim());
2708
2708
  }
2709
2709
  /* @__NO_SIDE_EFFECTS__ */
2710
2710
  function _toLowerCase() {
2711
- return /* @__PURE__ */ _overwrite((input) => input.toLowerCase());
2711
+ return /* @__PURE__ */ _overwrite((input$1) => input$1.toLowerCase());
2712
2712
  }
2713
2713
  /* @__NO_SIDE_EFFECTS__ */
2714
2714
  function _toUpperCase() {
2715
- return /* @__PURE__ */ _overwrite((input) => input.toUpperCase());
2715
+ return /* @__PURE__ */ _overwrite((input$1) => input$1.toUpperCase());
2716
2716
  }
2717
2717
  /* @__NO_SIDE_EFFECTS__ */
2718
2718
  function _slugify() {
2719
- return /* @__PURE__ */ _overwrite((input) => slugify(input));
2719
+ return /* @__PURE__ */ _overwrite((input$1) => slugify(input$1));
2720
2720
  }
2721
2721
  /* @__NO_SIDE_EFFECTS__ */
2722
2722
  function _array(Class, element, params) {
@@ -4214,7 +4214,13 @@ const _achasoft_dsh_advanced_sidebar_advancedSidebar_describe_result$schema = ob
4214
4214
  "available": boolean().readonly(),
4215
4215
  "reason": string().readonly().optional(),
4216
4216
  "detail": string().readonly().optional(),
4217
- "running": number().readonly()
4217
+ "running": number().readonly(),
4218
+ "surface": object({
4219
+ "fileRoute": string().readonly(),
4220
+ "proxyRoute": string().readonly(),
4221
+ "available": boolean().readonly(),
4222
+ "reason": string().readonly().optional()
4223
+ }).readonly().optional()
4218
4224
  }).readonly(),
4219
4225
  "tasks": object({
4220
4226
  "available": boolean().readonly(),
@@ -4285,7 +4291,11 @@ const _achasoft_dsh_advanced_sidebar_advancedSidebar_describe_result$schema = ob
4285
4291
  "maxPreviews": number().readonly(),
4286
4292
  "previewReadyTimeoutMs": number().readonly(),
4287
4293
  "previewScrollback": number().readonly(),
4288
- "previewGraceMs": number().readonly()
4294
+ "previewGraceMs": number().readonly(),
4295
+ "previewMaxFileBytes": number().readonly(),
4296
+ "previewProxyTimeoutMs": number().readonly(),
4297
+ "previewCommandTimeoutMs": number().readonly(),
4298
+ "previewBindTtlMs": number().readonly()
4289
4299
  }).readonly(),
4290
4300
  "readAt": number().readonly()
4291
4301
  });
@@ -5367,6 +5377,192 @@ const _achasoft_dsh_advanced_sidebar_advancedSidebar_previewStop_result$schema =
5367
5377
  ]).readonly(),
5368
5378
  "message": string().readonly()
5369
5379
  })]);
5380
+ const _achasoft_dsh_advanced_sidebar_advancedSidebar_previewFileInfo_parameter_0$schema = object({
5381
+ "workspacePath": string().readonly(),
5382
+ "path": string().readonly()
5383
+ });
5384
+ const _achasoft_dsh_advanced_sidebar_advancedSidebar_previewFileInfo_result$schema = union([object({
5385
+ "ok": literal(true).readonly(),
5386
+ "path": string().readonly(),
5387
+ "name": string().readonly(),
5388
+ "kind": union([
5389
+ literal("iframe"),
5390
+ literal("markdown"),
5391
+ literal("image"),
5392
+ literal("media"),
5393
+ literal("pdf"),
5394
+ literal("text"),
5395
+ literal("other")
5396
+ ]).readonly(),
5397
+ "contentType": string().readonly(),
5398
+ "bytes": number().readonly(),
5399
+ "withinLimit": boolean().readonly(),
5400
+ "url": string().readonly().optional(),
5401
+ "token": string().readonly(),
5402
+ "regular": boolean().readonly()
5403
+ }), object({
5404
+ "ok": literal(false).readonly(),
5405
+ "code": union([
5406
+ literal("no-filesystem"),
5407
+ literal("path-denied"),
5408
+ literal("not-a-file"),
5409
+ literal("read-failed")
5410
+ ]).readonly(),
5411
+ "message": string().readonly()
5412
+ })]);
5413
+ const _achasoft_dsh_advanced_sidebar_advancedSidebar_previewPoll_parameter_0$schema = object({
5414
+ "clientId": string().readonly(),
5415
+ "sessionId": string().readonly(),
5416
+ "mounted": boolean().readonly(),
5417
+ "bind": object({
5418
+ "clientId": string().readonly(),
5419
+ "sessionId": string().readonly(),
5420
+ "mode": union([
5421
+ literal("server"),
5422
+ literal("file"),
5423
+ literal("url"),
5424
+ literal("scratchpad")
5425
+ ]).readonly(),
5426
+ "filePath": string().readonly().optional(),
5427
+ "workspacePath": string().readonly().optional(),
5428
+ "url": string().readonly().optional(),
5429
+ "inspectable": boolean().readonly(),
5430
+ "width": number().readonly(),
5431
+ "height": number().readonly()
5432
+ }).readonly()
5433
+ });
5434
+ const _achasoft_dsh_advanced_sidebar_advancedSidebar_previewPoll_result$schema = union([object({
5435
+ "ok": literal(true).readonly(),
5436
+ "message": object({
5437
+ "commands": array(object({
5438
+ "id": string().readonly(),
5439
+ "clientId": string().readonly(),
5440
+ "kind": union([
5441
+ literal("open"),
5442
+ literal("dom"),
5443
+ literal("eval"),
5444
+ literal("console"),
5445
+ literal("click"),
5446
+ literal("input"),
5447
+ literal("reload"),
5448
+ literal("resize"),
5449
+ literal("close")
5450
+ ]).readonly(),
5451
+ "selector": string().readonly().optional(),
5452
+ "expression": string().readonly().optional(),
5453
+ "cursor": number().readonly().optional(),
5454
+ "text": string().readonly().optional(),
5455
+ "key": string().readonly().optional(),
5456
+ "width": number().readonly().optional(),
5457
+ "height": number().readonly().optional(),
5458
+ "timeoutMs": number().readonly()
5459
+ })).readonly(),
5460
+ "controls": array(object({
5461
+ "control": literal("open").readonly(),
5462
+ "open": object({
5463
+ "clientId": string().readonly(),
5464
+ "mode": union([
5465
+ literal("server"),
5466
+ literal("file"),
5467
+ literal("url"),
5468
+ literal("scratchpad")
5469
+ ]).readonly(),
5470
+ "filePath": string().readonly().optional(),
5471
+ "url": string().readonly().optional(),
5472
+ "workspacePath": string().readonly().optional()
5473
+ }).readonly()
5474
+ })).readonly()
5475
+ }).readonly(),
5476
+ "bindTtlMs": number().readonly()
5477
+ }), object({
5478
+ "ok": literal(false).readonly(),
5479
+ "code": union([literal("no-subprocess"), literal("closed")]).readonly(),
5480
+ "message": string().readonly()
5481
+ })]);
5482
+ const _achasoft_dsh_advanced_sidebar_advancedSidebar_previewResult_parameter_0$schema = object({
5483
+ "clientId": string().readonly(),
5484
+ "id": string().readonly(),
5485
+ "ok": boolean().readonly(),
5486
+ "error": string().readonly().optional(),
5487
+ "result": union([
5488
+ object({
5489
+ "kind": literal("dom").readonly(),
5490
+ "selector": string().readonly(),
5491
+ "viewport": object({
5492
+ "width": number().readonly(),
5493
+ "height": number().readonly()
5494
+ }).readonly(),
5495
+ "nodes": array(object({
5496
+ "tag": string().readonly(),
5497
+ "selector": string().readonly(),
5498
+ "text": string().readonly(),
5499
+ "display": string().readonly(),
5500
+ "box": object({
5501
+ "x": number().readonly(),
5502
+ "y": number().readonly(),
5503
+ "width": number().readonly(),
5504
+ "height": number().readonly()
5505
+ }).readonly(),
5506
+ "depth": number().readonly()
5507
+ })).readonly(),
5508
+ "text": string().readonly(),
5509
+ "truncated": boolean().readonly(),
5510
+ "url": string().readonly()
5511
+ }),
5512
+ object({
5513
+ "kind": literal("eval").readonly(),
5514
+ "value": string().readonly(),
5515
+ "note": string().readonly().optional(),
5516
+ "truncated": boolean().readonly()
5517
+ }),
5518
+ object({
5519
+ "kind": literal("console").readonly(),
5520
+ "entries": array(object({
5521
+ "level": union([
5522
+ literal("log"),
5523
+ literal("info"),
5524
+ literal("warn"),
5525
+ literal("error"),
5526
+ literal("uncaught"),
5527
+ literal("rejection")
5528
+ ]).readonly(),
5529
+ "text": string().readonly(),
5530
+ "at": number().readonly()
5531
+ })).readonly(),
5532
+ "cursor": number().readonly(),
5533
+ "lossy": boolean().readonly()
5534
+ }),
5535
+ object({
5536
+ "kind": literal("ack").readonly(),
5537
+ "detail": string().readonly(),
5538
+ "width": number().readonly().optional(),
5539
+ "height": number().readonly().optional()
5540
+ })
5541
+ ]).readonly().optional(),
5542
+ "console": array(object({
5543
+ "level": union([
5544
+ literal("log"),
5545
+ literal("info"),
5546
+ literal("warn"),
5547
+ literal("error"),
5548
+ literal("uncaught"),
5549
+ literal("rejection")
5550
+ ]).readonly(),
5551
+ "text": string().readonly(),
5552
+ "at": number().readonly()
5553
+ })).readonly().optional()
5554
+ });
5555
+ const _achasoft_dsh_advanced_sidebar_advancedSidebar_previewResult_result$schema = union([object({ "ok": literal(true).readonly() }), object({
5556
+ "ok": literal(false).readonly(),
5557
+ "code": union([literal("no-subprocess"), literal("closed")]).readonly(),
5558
+ "message": string().readonly()
5559
+ })]);
5560
+ const _achasoft_dsh_advanced_sidebar_advancedSidebar_previewRelease_parameter_0$schema = object({ "clientId": string().readonly() });
5561
+ const _achasoft_dsh_advanced_sidebar_advancedSidebar_previewRelease_result$schema = union([object({ "ok": literal(true).readonly() }), object({
5562
+ "ok": literal(false).readonly(),
5563
+ "code": union([literal("no-subprocess"), literal("closed")]).readonly(),
5564
+ "message": string().readonly()
5565
+ })]);
5370
5566
  const _achasoft_dsh_advanced_sidebar_advancedSidebar_readFile_parameter_0$schema = object({
5371
5567
  "path": string().readonly(),
5372
5568
  "workspacePath": string().readonly()
@@ -5558,7 +5754,7 @@ const TYPERT_REMOTE = {
5558
5754
  },
5559
5755
  sourceLocation: {
5560
5756
  "file": "src/host/index.ts",
5561
- "line": 464,
5757
+ "line": 590,
5562
5758
  "column": 3
5563
5759
  }
5564
5760
  },
@@ -5577,7 +5773,7 @@ const TYPERT_REMOTE = {
5577
5773
  },
5578
5774
  sourceLocation: {
5579
5775
  "file": "src/host/index.ts",
5580
- "line": 234,
5776
+ "line": 267,
5581
5777
  "column": 3
5582
5778
  }
5583
5779
  },
@@ -5605,7 +5801,7 @@ const TYPERT_REMOTE = {
5605
5801
  },
5606
5802
  sourceLocation: {
5607
5803
  "file": "src/host/index.ts",
5608
- "line": 274,
5804
+ "line": 307,
5609
5805
  "column": 3
5610
5806
  }
5611
5807
  },
@@ -5633,7 +5829,7 @@ const TYPERT_REMOTE = {
5633
5829
  },
5634
5830
  sourceLocation: {
5635
5831
  "file": "src/host/index.ts",
5636
- "line": 263,
5832
+ "line": 296,
5637
5833
  "column": 3
5638
5834
  }
5639
5835
  },
@@ -5661,7 +5857,7 @@ const TYPERT_REMOTE = {
5661
5857
  },
5662
5858
  sourceLocation: {
5663
5859
  "file": "src/host/index.ts",
5664
- "line": 285,
5860
+ "line": 318,
5665
5861
  "column": 3
5666
5862
  }
5667
5863
  },
@@ -5689,7 +5885,7 @@ const TYPERT_REMOTE = {
5689
5885
  },
5690
5886
  sourceLocation: {
5691
5887
  "file": "src/host/index.ts",
5692
- "line": 296,
5888
+ "line": 329,
5693
5889
  "column": 3
5694
5890
  }
5695
5891
  },
@@ -5717,7 +5913,7 @@ const TYPERT_REMOTE = {
5717
5913
  },
5718
5914
  sourceLocation: {
5719
5915
  "file": "src/host/index.ts",
5720
- "line": 307,
5916
+ "line": 340,
5721
5917
  "column": 3
5722
5918
  }
5723
5919
  },
@@ -5745,7 +5941,7 @@ const TYPERT_REMOTE = {
5745
5941
  },
5746
5942
  sourceLocation: {
5747
5943
  "file": "src/host/index.ts",
5748
- "line": 320,
5944
+ "line": 351,
5749
5945
  "column": 3
5750
5946
  }
5751
5947
  },
@@ -5773,7 +5969,7 @@ const TYPERT_REMOTE = {
5773
5969
  },
5774
5970
  sourceLocation: {
5775
5971
  "file": "src/host/index.ts",
5776
- "line": 333,
5972
+ "line": 362,
5777
5973
  "column": 3
5778
5974
  }
5779
5975
  },
@@ -5801,7 +5997,7 @@ const TYPERT_REMOTE = {
5801
5997
  },
5802
5998
  sourceLocation: {
5803
5999
  "file": "src/host/index.ts",
5804
- "line": 369,
6000
+ "line": 426,
5805
6001
  "column": 3
5806
6002
  }
5807
6003
  },
@@ -5829,7 +6025,7 @@ const TYPERT_REMOTE = {
5829
6025
  },
5830
6026
  sourceLocation: {
5831
6027
  "file": "src/host/index.ts",
5832
- "line": 433,
6028
+ "line": 560,
5833
6029
  "column": 3
5834
6030
  }
5835
6031
  },
@@ -5857,7 +6053,7 @@ const TYPERT_REMOTE = {
5857
6053
  },
5858
6054
  sourceLocation: {
5859
6055
  "file": "src/host/index.ts",
5860
- "line": 380,
6056
+ "line": 437,
5861
6057
  "column": 3
5862
6058
  }
5863
6059
  },
@@ -5884,7 +6080,7 @@ const TYPERT_REMOTE = {
5884
6080
  },
5885
6081
  sourceLocation: {
5886
6082
  "file": "src/host/index.ts",
5887
- "line": 411,
6083
+ "line": 468,
5888
6084
  "column": 3
5889
6085
  }
5890
6086
  },
@@ -5912,7 +6108,7 @@ const TYPERT_REMOTE = {
5912
6108
  },
5913
6109
  sourceLocation: {
5914
6110
  "file": "src/host/index.ts",
5915
- "line": 391,
6111
+ "line": 448,
5916
6112
  "column": 3
5917
6113
  }
5918
6114
  },
@@ -5939,7 +6135,116 @@ const TYPERT_REMOTE = {
5939
6135
  },
5940
6136
  sourceLocation: {
5941
6137
  "file": "src/host/index.ts",
5942
- "line": 401,
6138
+ "line": 458,
6139
+ "column": 3
6140
+ }
6141
+ },
6142
+ {
6143
+ id: "@achasoft/dsh-advanced-sidebar#advancedSidebar/previewFileInfo",
6144
+ service: "advancedSidebar",
6145
+ namespace: "advancedSidebar",
6146
+ method: "previewFileInfo",
6147
+ invocation: { kind: "direct" },
6148
+ parameters: [{
6149
+ name: "request",
6150
+ wire: "request",
6151
+ source: "json",
6152
+ codec: {
6153
+ mode: "strict",
6154
+ typeSymbol: "../src/host/types.ts#PreviewFileInfoRequest",
6155
+ schema: _achasoft_dsh_advanced_sidebar_advancedSidebar_previewFileInfo_parameter_0$schema
6156
+ }
6157
+ }],
6158
+ cancellation: { parameter: "signal" },
6159
+ result: {
6160
+ mode: "strict",
6161
+ typeSymbol: "../src/host/types.ts#PreviewFileInfoResult",
6162
+ schema: _achasoft_dsh_advanced_sidebar_advancedSidebar_previewFileInfo_result$schema
6163
+ },
6164
+ sourceLocation: {
6165
+ "file": "src/host/index.ts",
6166
+ "line": 483,
6167
+ "column": 3
6168
+ }
6169
+ },
6170
+ {
6171
+ id: "@achasoft/dsh-advanced-sidebar#advancedSidebar/previewPoll",
6172
+ service: "advancedSidebar",
6173
+ namespace: "advancedSidebar",
6174
+ method: "previewPoll",
6175
+ invocation: { kind: "direct" },
6176
+ parameters: [{
6177
+ name: "request",
6178
+ wire: "request",
6179
+ source: "json",
6180
+ codec: {
6181
+ mode: "strict",
6182
+ typeSymbol: "../src/host/types.ts#PreviewPollRequest",
6183
+ schema: _achasoft_dsh_advanced_sidebar_advancedSidebar_previewPoll_parameter_0$schema
6184
+ }
6185
+ }],
6186
+ result: {
6187
+ mode: "strict",
6188
+ typeSymbol: "../src/host/types.ts#PreviewPollResult",
6189
+ schema: _achasoft_dsh_advanced_sidebar_advancedSidebar_previewPoll_result$schema
6190
+ },
6191
+ sourceLocation: {
6192
+ "file": "src/host/index.ts",
6193
+ "line": 498,
6194
+ "column": 3
6195
+ }
6196
+ },
6197
+ {
6198
+ id: "@achasoft/dsh-advanced-sidebar#advancedSidebar/previewResult",
6199
+ service: "advancedSidebar",
6200
+ namespace: "advancedSidebar",
6201
+ method: "previewResult",
6202
+ invocation: { kind: "direct" },
6203
+ parameters: [{
6204
+ name: "request",
6205
+ wire: "request",
6206
+ source: "json",
6207
+ codec: {
6208
+ mode: "strict",
6209
+ typeSymbol: "../src/host/types.ts#PreviewResultRequest",
6210
+ schema: _achasoft_dsh_advanced_sidebar_advancedSidebar_previewResult_parameter_0$schema
6211
+ }
6212
+ }],
6213
+ result: {
6214
+ mode: "strict",
6215
+ typeSymbol: "../src/host/types.ts#PreviewResultAck",
6216
+ schema: _achasoft_dsh_advanced_sidebar_advancedSidebar_previewResult_result$schema
6217
+ },
6218
+ sourceLocation: {
6219
+ "file": "src/host/index.ts",
6220
+ "line": 516,
6221
+ "column": 3
6222
+ }
6223
+ },
6224
+ {
6225
+ id: "@achasoft/dsh-advanced-sidebar#advancedSidebar/previewRelease",
6226
+ service: "advancedSidebar",
6227
+ namespace: "advancedSidebar",
6228
+ method: "previewRelease",
6229
+ invocation: { kind: "direct" },
6230
+ parameters: [{
6231
+ name: "request",
6232
+ wire: "request",
6233
+ source: "json",
6234
+ codec: {
6235
+ mode: "strict",
6236
+ typeSymbol: "../src/host/types.ts#PreviewReleaseRequest",
6237
+ schema: _achasoft_dsh_advanced_sidebar_advancedSidebar_previewRelease_parameter_0$schema
6238
+ }
6239
+ }],
6240
+ result: {
6241
+ mode: "strict",
6242
+ typeSymbol: "../src/host/types.ts#PreviewReleaseResult",
6243
+ schema: _achasoft_dsh_advanced_sidebar_advancedSidebar_previewRelease_result$schema
6244
+ },
6245
+ sourceLocation: {
6246
+ "file": "src/host/index.ts",
6247
+ "line": 536,
5943
6248
  "column": 3
5944
6249
  }
5945
6250
  },
@@ -5967,7 +6272,7 @@ const TYPERT_REMOTE = {
5967
6272
  },
5968
6273
  sourceLocation: {
5969
6274
  "file": "src/host/index.ts",
5970
- "line": 422,
6275
+ "line": 549,
5971
6276
  "column": 3
5972
6277
  }
5973
6278
  },
@@ -5994,7 +6299,7 @@ const TYPERT_REMOTE = {
5994
6299
  },
5995
6300
  sourceLocation: {
5996
6301
  "file": "src/host/index.ts",
5997
- "line": 443,
6302
+ "line": 570,
5998
6303
  "column": 3
5999
6304
  }
6000
6305
  },
@@ -6021,7 +6326,7 @@ const TYPERT_REMOTE = {
6021
6326
  },
6022
6327
  sourceLocation: {
6023
6328
  "file": "src/host/index.ts",
6024
- "line": 453,
6329
+ "line": 580,
6025
6330
  "column": 3
6026
6331
  }
6027
6332
  },
@@ -6048,7 +6353,7 @@ const TYPERT_REMOTE = {
6048
6353
  },
6049
6354
  sourceLocation: {
6050
6355
  "file": "src/host/index.ts",
6051
- "line": 358,
6356
+ "line": 415,
6052
6357
  "column": 3
6053
6358
  }
6054
6359
  },
@@ -6076,7 +6381,7 @@ const TYPERT_REMOTE = {
6076
6381
  },
6077
6382
  sourceLocation: {
6078
6383
  "file": "src/host/index.ts",
6079
- "line": 318,
6384
+ "line": 375,
6080
6385
  "column": 3
6081
6386
  }
6082
6387
  },
@@ -6103,7 +6408,7 @@ const TYPERT_REMOTE = {
6103
6408
  },
6104
6409
  sourceLocation: {
6105
6410
  "file": "src/host/index.ts",
6106
- "line": 328,
6411
+ "line": 385,
6107
6412
  "column": 3
6108
6413
  }
6109
6414
  },
@@ -6130,7 +6435,7 @@ const TYPERT_REMOTE = {
6130
6435
  },
6131
6436
  sourceLocation: {
6132
6437
  "file": "src/host/index.ts",
6133
- "line": 348,
6438
+ "line": 405,
6134
6439
  "column": 3
6135
6440
  }
6136
6441
  },
@@ -6157,7 +6462,7 @@ const TYPERT_REMOTE = {
6157
6462
  },
6158
6463
  sourceLocation: {
6159
6464
  "file": "src/host/index.ts",
6160
- "line": 338,
6465
+ "line": 395,
6161
6466
  "column": 3
6162
6467
  }
6163
6468
  }
@@ -6677,92 +6982,92 @@ function PushGlyph({ size = 16, className }) {
6677
6982
 
6678
6983
  //#endregion
6679
6984
  //#region \0dsh-css:/Users/aslan_nejad/Desktop/DEV/achasoft/dsh-plugins/dsh-advanced-sidebar/src/client/ui/Ui.module.css.mjs
6680
- const css$5 = ".Txftaq_button{box-sizing:border-box;color:var(--dsw-alias-label-primary);font:inherit;white-space:nowrap;cursor:pointer;transition:background var(--ds-transition-duration-fast) var(--ds-ease-in-out), border-color var(--ds-transition-duration-fast) var(--ds-ease-in-out), color var(--ds-transition-duration-fast) var(--ds-ease-in-out);background:0 0;border:1px solid #0000;border-radius:6px;flex:none;justify-content:center;align-items:center;gap:6px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.Txftaq_button:disabled{opacity:.5;cursor:not-allowed}.Txftaq_button:focus-visible,.Txftaq_input:focus-visible,.Txftaq_trigger:focus-visible,.Txftaq_tab:focus-visible,.Txftaq_switch:focus-visible,.Txftaq_checkbox:focus-visible,.Txftaq_day:focus-visible,.Txftaq_item:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.Txftaq_sizeSm{height:28px;padding:0 10px;font-size:12px;line-height:18px}.Txftaq_sizeMd{height:32px;padding:0 12px}.Txftaq_sizeLg{height:36px;padding:0 16px}.Txftaq_sizeIcon{width:28px;height:28px;padding:0}.Txftaq_sizeIconLg{width:32px;height:32px;padding:0}.Txftaq_default{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.Txftaq_default:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.Txftaq_secondary{background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-primary)}.Txftaq_secondary:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Txftaq_outline{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary)}.Txftaq_outline:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Txftaq_ghost{color:var(--dsw-alias-label-secondary)}.Txftaq_ghost:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.Txftaq_ghost:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.Txftaq_destructive{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-inverted)}.Txftaq_destructive:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.Txftaq_buttonOn{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary)}.Txftaq_badge{box-sizing:border-box;white-space:nowrap;border:1px solid #0000;border-radius:10px;flex:none;align-items:center;gap:4px;height:20px;padding:0 8px;font-size:11px;font-weight:500;line-height:18px;display:inline-flex}.Txftaq_badgeDefault{background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-primary-foreground)}.Txftaq_badgeSecondary{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary)}.Txftaq_badgeOutline{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary)}.Txftaq_badgeSuccess{background:var(--dsw-alias-state-success-tertiary);color:var(--dsw-alias-state-success-primary)}.Txftaq_badgeWarning{background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-primary)}.Txftaq_badgeDestructive{background:var(--dsw-alias-state-error-secondary);color:var(--dsw-alias-state-error-primary)}.Txftaq_badgeCode{text-overflow:ellipsis;min-width:0;font-family:var(--ds-font-family-code);overflow:hidden}.Txftaq_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:6px;padding:0 10px;font-size:13px;line-height:20px}.Txftaq_input::placeholder{color:var(--dsw-alias-label-dimmed)}.Txftaq_input:disabled{opacity:.5;cursor:not-allowed}.Txftaq_textarea{resize:vertical;height:auto;min-height:64px;padding:8px 10px}.Txftaq_inputCode{font-family:var(--ds-font-family-code)}.Txftaq_inputNumber{appearance:textfield;width:96px}.Txftaq_inputNumber::-webkit-outer-spin-button,.Txftaq_inputNumber::-webkit-inner-spin-button{appearance:none;margin:0}.Txftaq_switch{background:var(--dsw-alias-bg-layer-3);cursor:pointer;width:34px;height:20px;transition:background var(--ds-transition-duration-fast) var(--ds-ease-in-out);border:1px solid #0000;border-radius:10px;flex:none;padding:0;position:relative}.Txftaq_switch[aria-checked=true]{background:var(--dsw-alias-brand-primary)}.Txftaq_switch:disabled{opacity:.5;cursor:not-allowed}.Txftaq_switchThumb{background:var(--dsw-alias-label-primary-inverted);width:14px;height:14px;transition:transform var(--ds-transition-duration-fast) var(--ds-ease-in-out);border-radius:7px;position:absolute;top:2px;left:2px}.Txftaq_switch[aria-checked=true] .Txftaq_switchThumb{transform:translate(14px)}.Txftaq_checkbox{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3);width:16px;height:16px;color:var(--dsw-alias-label-primary-foreground);cursor:pointer;background:0 0;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.Txftaq_checkbox[aria-checked=true]{border-color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-brand-primary)}.Txftaq_checkbox:disabled{opacity:.5;cursor:not-allowed}.Txftaq_checkRow{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:8px;font-size:12px;line-height:18px;display:inline-flex}.Txftaq_layer{z-index:60;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-menu);min-width:0;box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:8px;flex-direction:column;display:flex}.Txftaq_menu{overscroll-behavior:contain;min-width:200px;max-width:320px;padding:4px;overflow-y:auto}.Txftaq_item{box-sizing:border-box;width:100%;min-height:30px;color:var(--dsw-alias-label-primary);font:inherit;text-align:start;cursor:pointer;background:0 0;border:none;border-radius:4px;align-items:center;gap:8px;padding:4px 8px;font-size:13px;line-height:20px;display:flex}.Txftaq_item:hover:not(:disabled),.Txftaq_itemActive:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Txftaq_item:disabled{color:var(--dsw-alias-label-dimmed);cursor:not-allowed}.Txftaq_itemDanger{color:var(--dsw-alias-state-error-primary)}.Txftaq_itemDanger:hover:not(:disabled),.Txftaq_itemDanger.Txftaq_itemActive:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.Txftaq_itemIcon{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.Txftaq_itemDanger .Txftaq_itemIcon{color:var(--dsw-alias-state-error-primary)}.Txftaq_itemBody{flex:1;align-items:baseline;gap:8px;min-width:0;display:flex}.Txftaq_itemLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.Txftaq_itemNote{text-overflow:ellipsis;white-space:nowrap;max-width:140px;color:var(--dsw-alias-label-dimmed);flex:none;font-size:11px;line-height:16px;overflow:hidden}.Txftaq_itemChevron{color:var(--dsw-alias-label-tertiary);flex:none;display:inline-flex}.Txftaq_itemCheck{color:var(--dsw-alias-brand-primary);flex:none;display:inline-flex}.Txftaq_menuLabel{letter-spacing:.04em;text-transform:uppercase;color:var(--dsw-alias-label-dimmed);padding:6px 8px 4px;font-size:11px;font-weight:600;line-height:16px}.Txftaq_separator{border:none;border-top:1px solid var(--dsw-alias-border-l1);flex:none;margin:4px 0}.Txftaq_separatorVertical{border:none;border-left:1px solid var(--dsw-alias-border-l1);align-self:stretch;width:0;margin:0 4px}.Txftaq_trigger{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:0 8px 0 10px;font-size:13px;line-height:20px;display:inline-flex}.Txftaq_triggerValue{text-overflow:ellipsis;white-space:nowrap;text-align:start;flex:1;min-width:0;overflow:hidden}.Txftaq_trigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Txftaq_trigger:disabled{opacity:.5;cursor:not-allowed}.Txftaq_triggerPlaceholder{color:var(--dsw-alias-label-dimmed)}.Txftaq_tabs{background:var(--dsw-alias-bg-layer-1);border-radius:8px;align-items:center;gap:2px;min-width:0;padding:3px;display:flex}.Txftaq_tabsScroll{scrollbar-width:none;align-items:center;gap:2px;min-width:0;display:flex;overflow-x:auto}.Txftaq_tab{box-sizing:border-box;max-width:180px;height:24px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:5px;flex:none;align-items:center;gap:6px;padding:0 8px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.Txftaq_tab:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Txftaq_tabActive{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv1)}.Txftaq_tabLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.Txftaq_tabClose{width:16px;height:16px;color:var(--dsw-alias-label-dimmed);border-radius:4px;flex:none;justify-content:center;align-items:center;margin-right:-4px;display:inline-flex}.Txftaq_tabClose:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.Txftaq_dialogOverlay{z-index:80;background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.Txftaq_dialog{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);width:100%;max-width:440px;max-height:100%;box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:12px;flex-direction:column;gap:16px;padding:20px;display:flex;overflow:auto}.Txftaq_dialogTitle{margin:0;font-size:15px;font-weight:600;line-height:22px}.Txftaq_dialogDescription{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.Txftaq_dialogFooter{justify-content:flex-end;align-items:center;gap:8px;display:flex}.Txftaq_alert{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;align-items:flex-start;gap:10px;padding:10px 12px;font-size:12px;line-height:18px;display:flex}.Txftaq_alertIcon{color:var(--dsw-alias-label-tertiary);flex:none;margin-top:1px;display:inline-flex}.Txftaq_alertBody{overflow-wrap:anywhere;flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.Txftaq_alertTitle{font-weight:600}.Txftaq_alertDestructive{border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-state-error-secondary);color:var(--dsw-alias-state-error-primary)}.Txftaq_alertDestructive .Txftaq_alertIcon{color:var(--dsw-alias-state-error-primary)}.Txftaq_alertWarning{border-color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-label)}.Txftaq_alertWarning .Txftaq_alertIcon{color:var(--dsw-alias-state-warn-primary)}.Txftaq_alertSuccess{border-color:var(--dsw-alias-state-success-primary);background:var(--dsw-alias-state-success-tertiary);color:var(--dsw-alias-state-success-primary)}.Txftaq_alertSuccess .Txftaq_alertIcon{color:var(--dsw-alias-state-success-primary)}.Txftaq_tooltip{z-index:90;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-tooltip-bg);max-width:260px;box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;padding:5px 9px;font-size:12px;line-height:18px}.Txftaq_calendar{flex-direction:column;gap:8px;padding:10px;display:flex}.Txftaq_calendarHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.Txftaq_calendarMonth{text-align:center;flex:1;font-size:13px;font-weight:600;line-height:20px}.Txftaq_calendarGrid{grid-template-columns:repeat(7,30px);gap:2px;display:grid}.Txftaq_calendarWeekday{height:24px;color:var(--dsw-alias-label-dimmed);justify-content:center;align-items:center;font-size:11px;font-weight:500;line-height:16px;display:flex}.Txftaq_day{box-sizing:border-box;width:30px;height:30px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:12px;line-height:18px;display:inline-flex}.Txftaq_day:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Txftaq_dayOutside{color:var(--dsw-alias-label-dimmed)}.Txftaq_dayToday{border-color:var(--dsw-alias-border-l3)}.Txftaq_daySelected,.Txftaq_daySelected:hover:not(:disabled){background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-primary-foreground)}.Txftaq_day:disabled{opacity:.4;cursor:not-allowed}.Txftaq_calendarFoot{border-top:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:center;gap:8px;padding-top:2px;display:flex}.Txftaq_muted{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.Txftaq_srOnly{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}";
6681
- const tagId$5 = "@achasoft/dsh-advanced-sidebar/Ui.module.css";
6682
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
6985
+ const css$6 = ".Txftaq_button{box-sizing:border-box;color:var(--dsw-alias-label-primary);font:inherit;white-space:nowrap;cursor:pointer;transition:background var(--ds-transition-duration-fast) var(--ds-ease-in-out), border-color var(--ds-transition-duration-fast) var(--ds-ease-in-out), color var(--ds-transition-duration-fast) var(--ds-ease-in-out);background:0 0;border:1px solid #0000;border-radius:6px;flex:none;justify-content:center;align-items:center;gap:6px;font-size:13px;font-weight:500;line-height:20px;display:inline-flex}.Txftaq_button:disabled{opacity:.5;cursor:not-allowed}.Txftaq_button:focus-visible,.Txftaq_input:focus-visible,.Txftaq_trigger:focus-visible,.Txftaq_tab:focus-visible,.Txftaq_switch:focus-visible,.Txftaq_checkbox:focus-visible,.Txftaq_day:focus-visible,.Txftaq_item:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.Txftaq_sizeSm{height:28px;padding:0 10px;font-size:12px;line-height:18px}.Txftaq_sizeMd{height:32px;padding:0 12px}.Txftaq_sizeLg{height:36px;padding:0 16px}.Txftaq_sizeIcon{width:28px;height:28px;padding:0}.Txftaq_sizeIconLg{width:32px;height:32px;padding:0}.Txftaq_default{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.Txftaq_default:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.Txftaq_secondary{background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-primary)}.Txftaq_secondary:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Txftaq_outline{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary)}.Txftaq_outline:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Txftaq_ghost{color:var(--dsw-alias-label-secondary)}.Txftaq_ghost:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.Txftaq_ghost:active:not(:disabled){background:var(--dsw-alias-interactive-bg-active)}.Txftaq_destructive{background:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary-inverted)}.Txftaq_destructive:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.Txftaq_buttonOn{background:var(--dsw-alias-interactive-bg-active);color:var(--dsw-alias-label-primary)}.Txftaq_badge{box-sizing:border-box;white-space:nowrap;border:1px solid #0000;border-radius:10px;flex:none;align-items:center;gap:4px;height:20px;padding:0 8px;font-size:11px;font-weight:500;line-height:18px;display:inline-flex}.Txftaq_badgeDefault{background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-primary-foreground)}.Txftaq_badgeSecondary{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary)}.Txftaq_badgeOutline{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary)}.Txftaq_badgeSuccess{background:var(--dsw-alias-state-success-tertiary);color:var(--dsw-alias-state-success-primary)}.Txftaq_badgeWarning{background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-primary)}.Txftaq_badgeDestructive{background:var(--dsw-alias-state-error-secondary);color:var(--dsw-alias-state-error-primary)}.Txftaq_badgeCode{text-overflow:ellipsis;min-width:0;font-family:var(--ds-font-family-code);overflow:hidden}.Txftaq_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:6px;padding:0 10px;font-size:13px;line-height:20px}.Txftaq_input::placeholder{color:var(--dsw-alias-label-dimmed)}.Txftaq_input:disabled{opacity:.5;cursor:not-allowed}.Txftaq_textarea{resize:vertical;height:auto;min-height:64px;padding:8px 10px}.Txftaq_inputCode{font-family:var(--ds-font-family-code)}.Txftaq_inputNumber{appearance:textfield;width:96px}.Txftaq_inputNumber::-webkit-outer-spin-button,.Txftaq_inputNumber::-webkit-inner-spin-button{appearance:none;margin:0}.Txftaq_switch{background:var(--dsw-alias-bg-layer-3);cursor:pointer;width:34px;height:20px;transition:background var(--ds-transition-duration-fast) var(--ds-ease-in-out);border:1px solid #0000;border-radius:10px;flex:none;padding:0;position:relative}.Txftaq_switch[aria-checked=true]{background:var(--dsw-alias-brand-primary)}.Txftaq_switch:disabled{opacity:.5;cursor:not-allowed}.Txftaq_switchThumb{background:var(--dsw-alias-label-primary-inverted);width:14px;height:14px;transition:transform var(--ds-transition-duration-fast) var(--ds-ease-in-out);border-radius:7px;position:absolute;top:2px;left:2px}.Txftaq_switch[aria-checked=true] .Txftaq_switchThumb{transform:translate(14px)}.Txftaq_checkbox{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l3);width:16px;height:16px;color:var(--dsw-alias-label-primary-foreground);cursor:pointer;background:0 0;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.Txftaq_checkbox[aria-checked=true]{border-color:var(--dsw-alias-brand-primary);background:var(--dsw-alias-brand-primary)}.Txftaq_checkbox:disabled{opacity:.5;cursor:not-allowed}.Txftaq_checkRow{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:8px;font-size:12px;line-height:18px;display:inline-flex}.Txftaq_layer{z-index:60;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-specific-menu);min-width:0;box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:8px;flex-direction:column;display:flex}.Txftaq_menu{overscroll-behavior:contain;min-width:200px;max-width:320px;padding:4px;overflow-y:auto}.Txftaq_item{box-sizing:border-box;width:100%;min-height:30px;color:var(--dsw-alias-label-primary);font:inherit;text-align:start;cursor:pointer;background:0 0;border:none;border-radius:4px;align-items:center;gap:8px;padding:4px 8px;font-size:13px;line-height:20px;display:flex}.Txftaq_item:hover:not(:disabled),.Txftaq_itemActive:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Txftaq_item:disabled{color:var(--dsw-alias-label-dimmed);cursor:not-allowed}.Txftaq_itemDanger{color:var(--dsw-alias-state-error-primary)}.Txftaq_itemDanger:hover:not(:disabled),.Txftaq_itemDanger.Txftaq_itemActive:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.Txftaq_itemIcon{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.Txftaq_itemDanger .Txftaq_itemIcon{color:var(--dsw-alias-state-error-primary)}.Txftaq_itemBody{flex:1;align-items:baseline;gap:8px;min-width:0;display:flex}.Txftaq_itemLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.Txftaq_itemNote{text-overflow:ellipsis;white-space:nowrap;max-width:140px;color:var(--dsw-alias-label-dimmed);flex:none;font-size:11px;line-height:16px;overflow:hidden}.Txftaq_itemChevron{color:var(--dsw-alias-label-tertiary);flex:none;display:inline-flex}.Txftaq_itemCheck{color:var(--dsw-alias-brand-primary);flex:none;display:inline-flex}.Txftaq_menuLabel{letter-spacing:.04em;text-transform:uppercase;color:var(--dsw-alias-label-dimmed);padding:6px 8px 4px;font-size:11px;font-weight:600;line-height:16px}.Txftaq_separator{border:none;border-top:1px solid var(--dsw-alias-border-l1);flex:none;margin:4px 0}.Txftaq_separatorVertical{border:none;border-left:1px solid var(--dsw-alias-border-l1);align-self:stretch;width:0;margin:0 4px}.Txftaq_trigger{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;align-items:center;gap:6px;padding:0 8px 0 10px;font-size:13px;line-height:20px;display:inline-flex}.Txftaq_triggerValue{text-overflow:ellipsis;white-space:nowrap;text-align:start;flex:1;min-width:0;overflow:hidden}.Txftaq_trigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Txftaq_trigger:disabled{opacity:.5;cursor:not-allowed}.Txftaq_triggerPlaceholder{color:var(--dsw-alias-label-dimmed)}.Txftaq_tabs{background:var(--dsw-alias-bg-layer-1);border-radius:8px;align-items:center;gap:2px;min-width:0;padding:3px;display:flex}.Txftaq_tabsScroll{scrollbar-width:none;align-items:center;gap:2px;min-width:0;display:flex;overflow-x:auto}.Txftaq_tab{box-sizing:border-box;max-width:180px;height:24px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:5px;flex:none;align-items:center;gap:6px;padding:0 8px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.Txftaq_tab:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.Txftaq_tabActive{background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv1)}.Txftaq_tabLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.Txftaq_tabClose{width:16px;height:16px;color:var(--dsw-alias-label-dimmed);border-radius:4px;flex:none;justify-content:center;align-items:center;margin-right:-4px;display:inline-flex}.Txftaq_tabClose:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.Txftaq_dialogOverlay{z-index:80;background:var(--dsw-alias-bg-mask-1);justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.Txftaq_dialog{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);width:100%;max-width:440px;max-height:100%;box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary);border-radius:12px;flex-direction:column;gap:16px;padding:20px;display:flex;overflow:auto}.Txftaq_dialogTitle{margin:0;font-size:15px;font-weight:600;line-height:22px}.Txftaq_dialogDescription{color:var(--dsw-alias-label-secondary);overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.Txftaq_dialogFooter{justify-content:flex-end;align-items:center;gap:8px;display:flex}.Txftaq_alert{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;align-items:flex-start;gap:10px;padding:10px 12px;font-size:12px;line-height:18px;display:flex}.Txftaq_alertIcon{color:var(--dsw-alias-label-tertiary);flex:none;margin-top:1px;display:inline-flex}.Txftaq_alertBody{overflow-wrap:anywhere;flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.Txftaq_alertTitle{font-weight:600}.Txftaq_alertDestructive{border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-state-error-secondary);color:var(--dsw-alias-state-error-primary)}.Txftaq_alertDestructive .Txftaq_alertIcon{color:var(--dsw-alias-state-error-primary)}.Txftaq_alertWarning{border-color:var(--dsw-alias-state-warn-primary);background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-label)}.Txftaq_alertWarning .Txftaq_alertIcon{color:var(--dsw-alias-state-warn-primary)}.Txftaq_alertSuccess{border-color:var(--dsw-alias-state-success-primary);background:var(--dsw-alias-state-success-tertiary);color:var(--dsw-alias-state-success-primary)}.Txftaq_alertSuccess .Txftaq_alertIcon{color:var(--dsw-alias-state-success-primary)}.Txftaq_tooltip{z-index:90;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-tooltip-bg);max-width:260px;box-shadow:var(--dsw-shadow-lv2);color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;padding:5px 9px;font-size:12px;line-height:18px}.Txftaq_calendar{flex-direction:column;gap:8px;padding:10px;display:flex}.Txftaq_calendarHead{justify-content:space-between;align-items:center;gap:8px;display:flex}.Txftaq_calendarMonth{text-align:center;flex:1;font-size:13px;font-weight:600;line-height:20px}.Txftaq_calendarGrid{grid-template-columns:repeat(7,30px);gap:2px;display:grid}.Txftaq_calendarWeekday{height:24px;color:var(--dsw-alias-label-dimmed);justify-content:center;align-items:center;font-size:11px;font-weight:500;line-height:16px;display:flex}.Txftaq_day{box-sizing:border-box;width:30px;height:30px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;justify-content:center;align-items:center;padding:0;font-size:12px;line-height:18px;display:inline-flex}.Txftaq_day:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.Txftaq_dayOutside{color:var(--dsw-alias-label-dimmed)}.Txftaq_dayToday{border-color:var(--dsw-alias-border-l3)}.Txftaq_daySelected,.Txftaq_daySelected:hover:not(:disabled){background:var(--dsw-alias-brand-primary);color:var(--dsw-alias-label-primary-foreground)}.Txftaq_day:disabled{opacity:.4;cursor:not-allowed}.Txftaq_calendarFoot{border-top:1px solid var(--dsw-alias-border-l1);justify-content:space-between;align-items:center;gap:8px;padding-top:2px;display:flex}.Txftaq_muted{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.Txftaq_srOnly{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}";
6986
+ const tagId$6 = "@achasoft/dsh-advanced-sidebar/Ui.module.css";
6987
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$6) + "]") === null) {
6683
6988
  const tag = document.createElement("style");
6684
6989
  tag.dataset.plugin = "@achasoft/dsh-advanced-sidebar";
6685
- tag.dataset.pluginCss = tagId$5;
6686
- tag.textContent = css$5;
6990
+ tag.dataset.pluginCss = tagId$6;
6991
+ tag.textContent = css$6;
6687
6992
  document.head.appendChild(tag);
6688
6993
  }
6689
6994
  var Ui_module_css_default = {
6690
- "dialogOverlay": "Txftaq_dialogOverlay",
6691
- "itemLabel": "Txftaq_itemLabel",
6692
- "badge": "Txftaq_badge",
6693
- "itemChevron": "Txftaq_itemChevron",
6694
- "default": "Txftaq_default",
6695
- "input": "Txftaq_input",
6696
- "badgeDestructive": "Txftaq_badgeDestructive",
6697
- "daySelected": "Txftaq_daySelected",
6698
- "srOnly": "Txftaq_srOnly",
6699
- "badgeWarning": "Txftaq_badgeWarning",
6700
- "sizeSm": "Txftaq_sizeSm",
6995
+ "alertIcon": "Txftaq_alertIcon",
6996
+ "menuLabel": "Txftaq_menuLabel",
6997
+ "day": "Txftaq_day",
6998
+ "dialogFooter": "Txftaq_dialogFooter",
6999
+ "sizeLg": "Txftaq_sizeLg",
7000
+ "destructive": "Txftaq_destructive",
6701
7001
  "sizeIcon": "Txftaq_sizeIcon",
7002
+ "alertBody": "Txftaq_alertBody",
7003
+ "buttonOn": "Txftaq_buttonOn",
7004
+ "inputCode": "Txftaq_inputCode",
7005
+ "dialog": "Txftaq_dialog",
7006
+ "daySelected": "Txftaq_daySelected",
7007
+ "tabLabel": "Txftaq_tabLabel",
7008
+ "input": "Txftaq_input",
7009
+ "badgeSecondary": "Txftaq_badgeSecondary",
6702
7010
  "badgeCode": "Txftaq_badgeCode",
6703
- "item": "Txftaq_item",
6704
7011
  "triggerPlaceholder": "Txftaq_triggerPlaceholder",
6705
- "buttonOn": "Txftaq_buttonOn",
6706
- "sizeLg": "Txftaq_sizeLg",
6707
- "menu": "Txftaq_menu",
6708
- "itemNote": "Txftaq_itemNote",
7012
+ "sizeMd": "Txftaq_sizeMd",
7013
+ "itemActive": "Txftaq_itemActive",
7014
+ "itemBody": "Txftaq_itemBody",
7015
+ "alertTitle": "Txftaq_alertTitle",
7016
+ "ghost": "Txftaq_ghost",
6709
7017
  "alertWarning": "Txftaq_alertWarning",
7018
+ "separator": "Txftaq_separator",
7019
+ "button": "Txftaq_button",
6710
7020
  "alertSuccess": "Txftaq_alertSuccess",
6711
- "textarea": "Txftaq_textarea",
6712
- "muted": "Txftaq_muted",
6713
- "inputNumber": "Txftaq_inputNumber",
6714
7021
  "calendar": "Txftaq_calendar",
6715
- "dayToday": "Txftaq_dayToday",
6716
- "tabsScroll": "Txftaq_tabsScroll",
6717
- "badgeOutline": "Txftaq_badgeOutline",
6718
- "triggerValue": "Txftaq_triggerValue",
6719
- "alertIcon": "Txftaq_alertIcon",
6720
- "outline": "Txftaq_outline",
6721
- "ghost": "Txftaq_ghost",
6722
- "switch": "Txftaq_switch",
6723
- "alert": "Txftaq_alert",
6724
- "alertDestructive": "Txftaq_alertDestructive",
6725
- "dialogTitle": "Txftaq_dialogTitle",
6726
- "tabs": "Txftaq_tabs",
6727
- "tabLabel": "Txftaq_tabLabel",
6728
- "dialogFooter": "Txftaq_dialogFooter",
6729
- "tabClose": "Txftaq_tabClose",
6730
- "destructive": "Txftaq_destructive",
7022
+ "itemCheck": "Txftaq_itemCheck",
6731
7023
  "trigger": "Txftaq_trigger",
6732
- "tab": "Txftaq_tab",
6733
- "checkRow": "Txftaq_checkRow",
7024
+ "checkbox": "Txftaq_checkbox",
7025
+ "badgeDefault": "Txftaq_badgeDefault",
7026
+ "switch": "Txftaq_switch",
7027
+ "dayToday": "Txftaq_dayToday",
7028
+ "item": "Txftaq_item",
6734
7029
  "layer": "Txftaq_layer",
6735
- "dialog": "Txftaq_dialog",
6736
- "calendarGrid": "Txftaq_calendarGrid",
6737
- "sizeIconLg": "Txftaq_sizeIconLg",
6738
- "day": "Txftaq_day",
6739
- "secondary": "Txftaq_secondary",
6740
- "tooltip": "Txftaq_tooltip",
6741
- "dayOutside": "Txftaq_dayOutside",
6742
- "itemBody": "Txftaq_itemBody",
6743
- "separatorVertical": "Txftaq_separatorVertical",
7030
+ "muted": "Txftaq_muted",
7031
+ "tabClose": "Txftaq_tabClose",
7032
+ "dialogOverlay": "Txftaq_dialogOverlay",
6744
7033
  "badgeSuccess": "Txftaq_badgeSuccess",
6745
- "alertTitle": "Txftaq_alertTitle",
7034
+ "badgeWarning": "Txftaq_badgeWarning",
7035
+ "sizeIconLg": "Txftaq_sizeIconLg",
7036
+ "tab": "Txftaq_tab",
6746
7037
  "itemDanger": "Txftaq_itemDanger",
6747
- "badgeSecondary": "Txftaq_badgeSecondary",
6748
- "tabActive": "Txftaq_tabActive",
6749
- "itemActive": "Txftaq_itemActive",
6750
- "calendarHead": "Txftaq_calendarHead",
6751
- "calendarFoot": "Txftaq_calendarFoot",
6752
- "button": "Txftaq_button",
6753
- "switchThumb": "Txftaq_switchThumb",
7038
+ "triggerValue": "Txftaq_triggerValue",
7039
+ "tooltip": "Txftaq_tooltip",
7040
+ "srOnly": "Txftaq_srOnly",
7041
+ "itemLabel": "Txftaq_itemLabel",
6754
7042
  "calendarWeekday": "Txftaq_calendarWeekday",
6755
- "checkbox": "Txftaq_checkbox",
6756
- "itemCheck": "Txftaq_itemCheck",
6757
- "sizeMd": "Txftaq_sizeMd",
6758
- "inputCode": "Txftaq_inputCode",
6759
- "separator": "Txftaq_separator",
7043
+ "calendarFoot": "Txftaq_calendarFoot",
7044
+ "badgeDestructive": "Txftaq_badgeDestructive",
7045
+ "separatorVertical": "Txftaq_separatorVertical",
7046
+ "badge": "Txftaq_badge",
7047
+ "tabsScroll": "Txftaq_tabsScroll",
7048
+ "itemChevron": "Txftaq_itemChevron",
7049
+ "dayOutside": "Txftaq_dayOutside",
7050
+ "sizeSm": "Txftaq_sizeSm",
6760
7051
  "dialogDescription": "Txftaq_dialogDescription",
6761
- "badgeDefault": "Txftaq_badgeDefault",
6762
- "menuLabel": "Txftaq_menuLabel",
6763
- "alertBody": "Txftaq_alertBody",
7052
+ "alertDestructive": "Txftaq_alertDestructive",
7053
+ "secondary": "Txftaq_secondary",
7054
+ "dialogTitle": "Txftaq_dialogTitle",
7055
+ "switchThumb": "Txftaq_switchThumb",
7056
+ "menu": "Txftaq_menu",
7057
+ "textarea": "Txftaq_textarea",
7058
+ "checkRow": "Txftaq_checkRow",
7059
+ "itemNote": "Txftaq_itemNote",
7060
+ "calendarHead": "Txftaq_calendarHead",
7061
+ "itemIcon": "Txftaq_itemIcon",
7062
+ "alert": "Txftaq_alert",
7063
+ "outline": "Txftaq_outline",
7064
+ "badgeOutline": "Txftaq_badgeOutline",
7065
+ "tabs": "Txftaq_tabs",
7066
+ "inputNumber": "Txftaq_inputNumber",
7067
+ "tabActive": "Txftaq_tabActive",
7068
+ "default": "Txftaq_default",
6764
7069
  "calendarMonth": "Txftaq_calendarMonth",
6765
- "itemIcon": "Txftaq_itemIcon"
7070
+ "calendarGrid": "Txftaq_calendarGrid"
6766
7071
  };
6767
7072
 
6768
7073
  //#endregion
@@ -6854,7 +7159,7 @@ const SIZES = {
6854
7159
  * @returns the button element.
6855
7160
  * @see {@link ButtonProps}
6856
7161
  */
6857
- const Button = (0, react.forwardRef)(function Button$1(props, ref) {
7162
+ const Button$1 = (0, react.forwardRef)(function Button$2(props, ref) {
6858
7163
  const { variant = "ghost", size = "md", icon, active, className, children, type,...rest } = props;
6859
7164
  return (0, react_jsx_runtime.jsxs)("button", {
6860
7165
  ref,
@@ -6936,7 +7241,7 @@ function Calendar(props) {
6936
7241
  (0, react_jsx_runtime.jsxs)("div", {
6937
7242
  className: Ui_module_css_default.calendarHead,
6938
7243
  children: [
6939
- (0, react_jsx_runtime.jsx)(Button, {
7244
+ (0, react_jsx_runtime.jsx)(Button$1, {
6940
7245
  size: "icon",
6941
7246
  "aria-label": previousLabel,
6942
7247
  onClick: () => {
@@ -6948,7 +7253,7 @@ function Calendar(props) {
6948
7253
  className: Ui_module_css_default.calendarMonth,
6949
7254
  children: monthName
6950
7255
  }),
6951
- (0, react_jsx_runtime.jsx)(Button, {
7256
+ (0, react_jsx_runtime.jsx)(Button$1, {
6952
7257
  size: "icon",
6953
7258
  "aria-label": nextLabel,
6954
7259
  onClick: () => {
@@ -6982,14 +7287,14 @@ function Calendar(props) {
6982
7287
  }),
6983
7288
  (0, react_jsx_runtime.jsxs)("div", {
6984
7289
  className: Ui_module_css_default.calendarFoot,
6985
- children: [(0, react_jsx_runtime.jsx)(Button, {
7290
+ children: [(0, react_jsx_runtime.jsx)(Button$1, {
6986
7291
  size: "sm",
6987
7292
  onClick: () => {
6988
7293
  setMonth(today);
6989
7294
  onValueChange(today);
6990
7295
  },
6991
7296
  children: todayLabel
6992
- }), clearLabel !== void 0 && onClear !== void 0 && (0, react_jsx_runtime.jsx)(Button, {
7297
+ }), clearLabel !== void 0 && onClear !== void 0 && (0, react_jsx_runtime.jsx)(Button$1, {
6993
7298
  size: "sm",
6994
7299
  onClick: onClear,
6995
7300
  children: clearLabel
@@ -7413,12 +7718,12 @@ function AlertDialog(props) {
7413
7718
  title,
7414
7719
  busy,
7415
7720
  ...description === void 0 ? {} : { description },
7416
- footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(Button, {
7721
+ footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(Button$1, {
7417
7722
  variant: "outline",
7418
7723
  disabled: busy,
7419
7724
  onClick: onClose,
7420
7725
  children: cancelLabel
7421
- }), (0, react_jsx_runtime.jsx)(Button, {
7726
+ }), (0, react_jsx_runtime.jsx)(Button$1, {
7422
7727
  variant: destructive ? "destructive" : "default",
7423
7728
  disabled: busy,
7424
7729
  onClick: onConfirm,
@@ -7947,85 +8252,85 @@ function CheckboxRow(props) {
7947
8252
 
7948
8253
  //#endregion
7949
8254
  //#region \0dsh-css:/Users/aslan_nejad/Desktop/DEV/achasoft/dsh-plugins/dsh-advanced-sidebar/src/client/panels/Panels.module.css.mjs
7950
- const css$4 = ".oiYQhW_toolbar{border-bottom:1px solid var(--dsw-alias-border-l2);min-height:38px;color:var(--dsw-alias-label-secondary);flex:none;align-items:center;gap:8px;padding:6px 10px;font-size:12px;line-height:18px;display:flex}.oiYQhW_spacer{flex:1;min-width:0}.oiYQhW_branch{text-overflow:ellipsis;white-space:nowrap;max-width:45%;color:var(--dsw-alias-label-primary);flex:none;font-weight:600;overflow:hidden}.oiYQhW_crumb{min-width:0;display:flex}.oiYQhW_scroll{flex:1;min-height:0;padding:8px 4px 12px;overflow:auto}.oiYQhW_split{flex-direction:column;flex:1;min-height:0;display:flex}.oiYQhW_split>.oiYQhW_scroll{border-bottom:1px solid var(--dsw-alias-border-l2);flex:45%}.oiYQhW_preview{flex:55%;min-height:0;padding:8px 12px 12px;overflow:auto}.oiYQhW_previewHead{align-items:center;gap:8px;margin-bottom:6px;display:flex}.oiYQhW_quiet{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin:8px 12px;font-size:12px;line-height:18px}.oiYQhW_quietInline{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);overflow:hidden}.oiYQhW_panelAlert{flex:none;margin:8px 12px}.oiYQhW_group{margin-bottom:10px}.oiYQhW_groupTitle{letter-spacing:.04em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;margin:6px 12px;font-size:11px;font-weight:600;line-height:16px;display:flex}.oiYQhW_groupCount{background:var(--dsw-alias-bg-module-platform);letter-spacing:0;border-radius:999px;padding:0 6px;font-weight:500}.oiYQhW_groupAction{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font:inherit;letter-spacing:0;text-transform:none;cursor:pointer;background:0 0;border-radius:6px;margin-left:auto;padding:1px 8px;font-size:11px;line-height:16px}.oiYQhW_groupAction:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.oiYQhW_groupAction:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.oiYQhW_fileBlock{flex-direction:column;display:flex}.oiYQhW_fileLine{align-items:center;min-width:0;display:flex}.oiYQhW_fileLine:hover{background:var(--dsw-alias-interactive-bg-hover)}.oiYQhW_fileLine:hover>.oiYQhW_fileRow:hover{background:0 0}.oiYQhW_fileBlockOpen>.oiYQhW_fileLine{background:var(--dsw-alias-interactive-bg-active)}.oiYQhW_rowAction{width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;opacity:0;background:0 0;border:none;border-radius:6px;flex:none;justify-content:center;align-items:center;margin-right:8px;display:inline-flex}.oiYQhW_fileLine:hover .oiYQhW_rowAction,.oiYQhW_rowAction:focus-visible{opacity:1}.oiYQhW_rowAction:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.oiYQhW_rowAction:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.oiYQhW_fileRow{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;padding:5px 12px;font-size:13px;line-height:20px;display:flex}.oiYQhW_fileRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.oiYQhW_fileRow:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.oiYQhW_fileRow:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.oiYQhW_fileRow:disabled:hover{background:0 0}.oiYQhW_fileRowOpen{background:var(--dsw-alias-interactive-bg-active)}.oiYQhW_filePath{flex:1;min-width:0;display:flex}.oiYQhW_pathHead{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.oiYQhW_pathTail{white-space:pre;flex:none}.oiYQhW_fileSize{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.oiYQhW_letter{text-align:center;width:16px;font-family:var(--ds-font-family-code);color:var(--dsw-alias-label-secondary);flex:none;font-size:11px;font-weight:600}.oiYQhW_letterA{color:var(--dsw-alias-state-success-primary)}.oiYQhW_letterD{color:var(--dsw-alias-state-error-primary)}.oiYQhW_letterU{color:var(--dsw-alias-state-warn-primary)}.oiYQhW_commitBox{border-bottom:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;gap:6px;padding:10px 12px;display:flex}.oiYQhW_commitMessage{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);width:100%;color:var(--dsw-alias-label-primary);font:inherit;resize:vertical;border-radius:8px;min-height:52px;padding:8px 10px;font-size:13px;line-height:20px}.oiYQhW_commitMessage:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.oiYQhW_commitMessage:disabled{color:var(--dsw-alias-label-tertiary)}.oiYQhW_commitRow{align-items:center;gap:8px;display:flex}.oiYQhW_commitHint{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin:0;font-size:11px;line-height:16px}.oiYQhW_diffBlock{padding:0 12px 10px 34px}.oiYQhW_copyButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border-radius:6px;align-items:center;gap:6px;margin-bottom:6px;padding:2px 8px;font-size:11px;line-height:18px;display:inline-flex}.oiYQhW_copyButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.oiYQhW_diff{background:var(--dsw-alias-markdown-code-block);font-family:var(--ds-font-family-code);white-space:pre;border-radius:8px;margin:0;padding:8px;font-size:12px;line-height:18px;overflow-x:auto}.oiYQhW_diffLine{display:inline}.oiYQhW_diffAdd{color:var(--dsw-alias-state-success-primary)}.oiYQhW_diffRemove{color:var(--dsw-alias-state-error-primary)}.oiYQhW_diffHunk{color:var(--dsw-alias-state-business-primary)}.oiYQhW_diffMeta{color:var(--dsw-alias-label-tertiary)}.oiYQhW_filterBar{border-bottom:1px solid var(--dsw-alias-border-l2);flex-wrap:wrap;flex:none;align-items:center;gap:8px;padding:8px 10px;display:flex}.oiYQhW_filterText{flex:140px;min-width:0}.oiYQhW_filterControl{flex:120px;min-width:0;max-width:180px}.oiYQhW_terminalTabs{border-bottom:1px solid var(--dsw-alias-border-l2);flex:none;align-items:center;padding:6px 8px;display:flex}.oiYQhW_terminalStack{flex:1;min-height:0;position:relative}.oiYQhW_terminalView{flex-direction:column;min-height:0;display:flex;position:absolute;inset:0}.oiYQhW_terminalViewHidden{visibility:hidden;pointer-events:none}.oiYQhW_terminalBox{background:var(--dsw-alias-bg-layer-1);cursor:text;flex:1;min-height:0;padding:8px 4px 8px 12px;overflow:hidden}.oiYQhW_previewText,.oiYQhW_terminalText{font-family:var(--ds-font-family-code);color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:12px;line-height:18px}.oiYQhW_taskBlock{flex-direction:column;display:flex}.oiYQhW_taskRow{align-items:center;gap:8px;padding:5px 12px 5px 4px;font-size:13px;line-height:20px;display:flex}.oiYQhW_taskRowSettled{color:var(--dsw-alias-label-tertiary)}.oiYQhW_taskDisclosure{width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;justify-content:center;align-items:center;display:inline-flex}.oiYQhW_taskDisclosure:hover{background:var(--dsw-alias-interactive-bg-hover)}.oiYQhW_taskDisclosureSpacer{flex:none;width:22px}.oiYQhW_taskDot{flex:none}.oiYQhW_taskKind{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:0 6px;font-size:11px;line-height:17px}.oiYQhW_taskLabel{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.oiYQhW_taskStatus{text-overflow:ellipsis;white-space:nowrap;max-width:35%;color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;overflow:hidden}.oiYQhW_taskDuration{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.oiYQhW_taskOutput{padding:0 12px 10px 34px}.oiYQhW_taskOutput>.oiYQhW_terminalText{background:var(--dsw-alias-markdown-code-block);border-radius:8px;max-height:320px;padding:8px;overflow:auto}.oiYQhW_previewPicker{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);max-width:45%;height:24px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;flex:none;padding:0 4px;font-size:11px}.oiYQhW_previewPicker:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.oiYQhW_addressBar{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);min-width:0;height:26px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:6px;flex:1;padding:0 8px;font-size:12px}.oiYQhW_addressBar:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.oiYQhW_previewStage{background:var(--dsw-alias-bg-layer-1);flex:1;justify-content:center;align-items:flex-start;min-height:0;display:flex;overflow:hidden}.oiYQhW_previewStageShort{flex:55%}.oiYQhW_previewFrame{background:var(--dsw-alias-bg-base);transform-origin:top;border:0;flex:none;width:100%;height:100%}.oiYQhW_previewLogs{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);flex:45%;min-height:0;padding:8px 12px 12px;overflow:auto}.oiYQhW_entryName{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}";
7951
- const tagId$4 = "@achasoft/dsh-advanced-sidebar/Panels.module.css";
7952
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
8255
+ const css$5 = ".oiYQhW_toolbar{border-bottom:1px solid var(--dsw-alias-border-l2);min-height:38px;color:var(--dsw-alias-label-secondary);flex:none;align-items:center;gap:8px;padding:6px 10px;font-size:12px;line-height:18px;display:flex}.oiYQhW_spacer{flex:1;min-width:0}.oiYQhW_branch{text-overflow:ellipsis;white-space:nowrap;max-width:45%;color:var(--dsw-alias-label-primary);flex:none;font-weight:600;overflow:hidden}.oiYQhW_crumb{min-width:0;display:flex}.oiYQhW_scroll{flex:1;min-height:0;padding:8px 4px 12px;overflow:auto}.oiYQhW_split{flex-direction:column;flex:1;min-height:0;display:flex}.oiYQhW_split>.oiYQhW_scroll{border-bottom:1px solid var(--dsw-alias-border-l2);flex:45%}.oiYQhW_preview{flex:55%;min-height:0;padding:8px 12px 12px;overflow:auto}.oiYQhW_previewHead{align-items:center;gap:8px;margin-bottom:6px;display:flex}.oiYQhW_quiet{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin:8px 12px;font-size:12px;line-height:18px}.oiYQhW_quietInline{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);overflow:hidden}.oiYQhW_panelAlert{flex:none;margin:8px 12px}.oiYQhW_group{margin-bottom:10px}.oiYQhW_groupTitle{letter-spacing:.04em;text-transform:uppercase;color:var(--dsw-alias-label-tertiary);align-items:center;gap:8px;margin:6px 12px;font-size:11px;font-weight:600;line-height:16px;display:flex}.oiYQhW_groupCount{background:var(--dsw-alias-bg-module-platform);letter-spacing:0;border-radius:999px;padding:0 6px;font-weight:500}.oiYQhW_groupAction{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font:inherit;letter-spacing:0;text-transform:none;cursor:pointer;background:0 0;border-radius:6px;margin-left:auto;padding:1px 8px;font-size:11px;line-height:16px}.oiYQhW_groupAction:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.oiYQhW_groupAction:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.oiYQhW_fileBlock{flex-direction:column;display:flex}.oiYQhW_fileLine{align-items:center;min-width:0;display:flex}.oiYQhW_fileLine:hover{background:var(--dsw-alias-interactive-bg-hover)}.oiYQhW_fileLine:hover>.oiYQhW_fileRow:hover{background:0 0}.oiYQhW_fileBlockOpen>.oiYQhW_fileLine{background:var(--dsw-alias-interactive-bg-active)}.oiYQhW_rowAction{width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;opacity:0;background:0 0;border:none;border-radius:6px;flex:none;justify-content:center;align-items:center;margin-right:8px;display:inline-flex}.oiYQhW_fileLine:hover .oiYQhW_rowAction,.oiYQhW_rowAction:focus-visible{opacity:1}.oiYQhW_rowAction:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.oiYQhW_rowAction:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.oiYQhW_fileRow{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;padding:5px 12px;font-size:13px;line-height:20px;display:flex}.oiYQhW_fileRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.oiYQhW_fileRow:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.oiYQhW_fileRow:disabled{color:var(--dsw-alias-label-dimmed);cursor:default}.oiYQhW_fileRow:disabled:hover{background:0 0}.oiYQhW_fileRowOpen{background:var(--dsw-alias-interactive-bg-active)}.oiYQhW_filePath{flex:1;min-width:0;display:flex}.oiYQhW_pathHead{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.oiYQhW_pathTail{white-space:pre;flex:none}.oiYQhW_fileSize{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.oiYQhW_letter{text-align:center;width:16px;font-family:var(--ds-font-family-code);color:var(--dsw-alias-label-secondary);flex:none;font-size:11px;font-weight:600}.oiYQhW_letterA{color:var(--dsw-alias-state-success-primary)}.oiYQhW_letterD{color:var(--dsw-alias-state-error-primary)}.oiYQhW_letterU{color:var(--dsw-alias-state-warn-primary)}.oiYQhW_commitBox{border-bottom:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;gap:6px;padding:10px 12px;display:flex}.oiYQhW_commitMessage{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);width:100%;color:var(--dsw-alias-label-primary);font:inherit;resize:vertical;border-radius:8px;min-height:52px;padding:8px 10px;font-size:13px;line-height:20px}.oiYQhW_commitMessage:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.oiYQhW_commitMessage:disabled{color:var(--dsw-alias-label-tertiary)}.oiYQhW_commitRow{align-items:center;gap:8px;display:flex}.oiYQhW_commitHint{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;margin:0;font-size:11px;line-height:16px}.oiYQhW_diffBlock{padding:0 12px 10px 34px}.oiYQhW_copyButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border-radius:6px;align-items:center;gap:6px;margin-bottom:6px;padding:2px 8px;font-size:11px;line-height:18px;display:inline-flex}.oiYQhW_copyButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.oiYQhW_diff{background:var(--dsw-alias-markdown-code-block);font-family:var(--ds-font-family-code);white-space:pre;border-radius:8px;margin:0;padding:8px;font-size:12px;line-height:18px;overflow-x:auto}.oiYQhW_diffLine{display:inline}.oiYQhW_diffAdd{color:var(--dsw-alias-state-success-primary)}.oiYQhW_diffRemove{color:var(--dsw-alias-state-error-primary)}.oiYQhW_diffHunk{color:var(--dsw-alias-state-business-primary)}.oiYQhW_diffMeta{color:var(--dsw-alias-label-tertiary)}.oiYQhW_filterBar{border-bottom:1px solid var(--dsw-alias-border-l2);flex-wrap:wrap;flex:none;align-items:center;gap:8px;padding:8px 10px;display:flex}.oiYQhW_filterText{flex:140px;min-width:0}.oiYQhW_filterControl{flex:120px;min-width:0;max-width:180px}.oiYQhW_terminalTabs{border-bottom:1px solid var(--dsw-alias-border-l2);flex:none;align-items:center;padding:6px 8px;display:flex}.oiYQhW_terminalStack{flex:1;min-height:0;position:relative}.oiYQhW_terminalView{flex-direction:column;min-height:0;display:flex;position:absolute;inset:0}.oiYQhW_terminalViewHidden{visibility:hidden;pointer-events:none}.oiYQhW_terminalBox{background:var(--dsw-alias-bg-layer-1);cursor:text;flex:1;min-height:0;padding:8px 4px 8px 12px;overflow:hidden}.oiYQhW_previewText,.oiYQhW_terminalText{font-family:var(--ds-font-family-code);color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;font-size:12px;line-height:18px}.oiYQhW_taskBlock{flex-direction:column;display:flex}.oiYQhW_taskRow{align-items:center;gap:8px;padding:5px 12px 5px 4px;font-size:13px;line-height:20px;display:flex}.oiYQhW_taskRowSettled{color:var(--dsw-alias-label-tertiary)}.oiYQhW_taskDisclosure{width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;flex:none;justify-content:center;align-items:center;display:inline-flex}.oiYQhW_taskDisclosure:hover{background:var(--dsw-alias-interactive-bg-hover)}.oiYQhW_taskDisclosureSpacer{flex:none;width:22px}.oiYQhW_taskDot{flex:none}.oiYQhW_taskKind{background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:0 6px;font-size:11px;line-height:17px}.oiYQhW_taskLabel{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.oiYQhW_taskStatus{text-overflow:ellipsis;white-space:nowrap;max-width:35%;color:var(--dsw-alias-label-tertiary);flex:none;font-size:11px;overflow:hidden}.oiYQhW_taskDuration{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;font-size:11px}.oiYQhW_taskOutput{padding:0 12px 10px 34px}.oiYQhW_taskOutput>.oiYQhW_terminalText{background:var(--dsw-alias-markdown-code-block);border-radius:8px;max-height:320px;padding:8px;overflow:auto}.oiYQhW_previewPicker{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);max-width:45%;height:24px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;border-radius:6px;flex:none;padding:0 4px;font-size:11px}.oiYQhW_previewPicker:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.oiYQhW_addressBar{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);min-width:0;height:26px;color:var(--dsw-alias-label-primary);font:inherit;border-radius:6px;flex:1;padding:0 8px;font-size:12px}.oiYQhW_addressBar:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.oiYQhW_previewStage{background:var(--dsw-alias-bg-layer-1);flex:1;justify-content:center;align-items:flex-start;min-height:0;display:flex;overflow:hidden}.oiYQhW_previewStageShort{flex:55%}.oiYQhW_previewFrame{background:var(--dsw-alias-bg-base);transform-origin:top;border:0;flex:none;width:100%;height:100%}.oiYQhW_previewLogs{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);flex:45%;min-height:0;padding:8px 12px 12px;overflow:auto}.oiYQhW_entryName{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}";
8256
+ const tagId$5 = "@achasoft/dsh-advanced-sidebar/Panels.module.css";
8257
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
7953
8258
  const tag = document.createElement("style");
7954
8259
  tag.dataset.plugin = "@achasoft/dsh-advanced-sidebar";
7955
- tag.dataset.pluginCss = tagId$4;
7956
- tag.textContent = css$4;
8260
+ tag.dataset.pluginCss = tagId$5;
8261
+ tag.textContent = css$5;
7957
8262
  document.head.appendChild(tag);
7958
8263
  }
7959
8264
  var Panels_module_css_default = {
7960
- "terminalTabs": "oiYQhW_terminalTabs",
7961
- "quiet": "oiYQhW_quiet",
8265
+ "taskLabel": "oiYQhW_taskLabel",
8266
+ "previewPicker": "oiYQhW_previewPicker",
8267
+ "filePath": "oiYQhW_filePath",
8268
+ "previewHead": "oiYQhW_previewHead",
8269
+ "terminalBox": "oiYQhW_terminalBox",
8270
+ "taskDot": "oiYQhW_taskDot",
7962
8271
  "entryName": "oiYQhW_entryName",
7963
- "groupAction": "oiYQhW_groupAction",
7964
- "rowAction": "oiYQhW_rowAction",
7965
- "copyButton": "oiYQhW_copyButton",
7966
- "terminalText": "oiYQhW_terminalText",
7967
- "diffLine": "oiYQhW_diffLine",
7968
- "terminalViewHidden": "oiYQhW_terminalViewHidden",
7969
- "branch": "oiYQhW_branch",
7970
- "preview": "oiYQhW_preview",
7971
- "commitBox": "oiYQhW_commitBox",
7972
- "split": "oiYQhW_split",
7973
- "panelAlert": "oiYQhW_panelAlert",
7974
- "fileBlock": "oiYQhW_fileBlock",
8272
+ "toolbar": "oiYQhW_toolbar",
8273
+ "taskBlock": "oiYQhW_taskBlock",
8274
+ "taskOutput": "oiYQhW_taskOutput",
8275
+ "taskRowSettled": "oiYQhW_taskRowSettled",
7975
8276
  "terminalStack": "oiYQhW_terminalStack",
7976
- "fileRowOpen": "oiYQhW_fileRowOpen",
8277
+ "commitHint": "oiYQhW_commitHint",
8278
+ "diffBlock": "oiYQhW_diffBlock",
7977
8279
  "previewText": "oiYQhW_previewText",
7978
- "taskStatus": "oiYQhW_taskStatus",
7979
- "toolbar": "oiYQhW_toolbar",
7980
- "scroll": "oiYQhW_scroll",
8280
+ "addressBar": "oiYQhW_addressBar",
8281
+ "preview": "oiYQhW_preview",
8282
+ "letterD": "oiYQhW_letterD",
8283
+ "diffRemove": "oiYQhW_diffRemove",
8284
+ "fileBlock": "oiYQhW_fileBlock",
8285
+ "quietInline": "oiYQhW_quietInline",
8286
+ "previewStageShort": "oiYQhW_previewStageShort",
8287
+ "pathTail": "oiYQhW_pathTail",
8288
+ "terminalViewHidden": "oiYQhW_terminalViewHidden",
8289
+ "fileLine": "oiYQhW_fileLine",
7981
8290
  "pathHead": "oiYQhW_pathHead",
7982
- "taskRowSettled": "oiYQhW_taskRowSettled",
8291
+ "diff": "oiYQhW_diff",
8292
+ "scroll": "oiYQhW_scroll",
8293
+ "diffHunk": "oiYQhW_diffHunk",
8294
+ "commitRow": "oiYQhW_commitRow",
8295
+ "quiet": "oiYQhW_quiet",
8296
+ "letterA": "oiYQhW_letterA",
8297
+ "taskKind": "oiYQhW_taskKind",
8298
+ "previewLogs": "oiYQhW_previewLogs",
8299
+ "fileSize": "oiYQhW_fileSize",
8300
+ "previewFrame": "oiYQhW_previewFrame",
8301
+ "taskDisclosure": "oiYQhW_taskDisclosure",
8302
+ "groupCount": "oiYQhW_groupCount",
8303
+ "fileRow": "oiYQhW_fileRow",
7983
8304
  "filterControl": "oiYQhW_filterControl",
7984
8305
  "taskDuration": "oiYQhW_taskDuration",
7985
- "letterD": "oiYQhW_letterD",
7986
- "terminalView": "oiYQhW_terminalView",
7987
- "previewFrame": "oiYQhW_previewFrame",
7988
- "taskDot": "oiYQhW_taskDot",
7989
- "diffHunk": "oiYQhW_diffHunk",
7990
8306
  "letter": "oiYQhW_letter",
7991
- "taskBlock": "oiYQhW_taskBlock",
7992
- "taskDisclosureSpacer": "oiYQhW_taskDisclosureSpacer",
7993
- "terminalBox": "oiYQhW_terminalBox",
7994
- "diff": "oiYQhW_diff",
7995
- "previewPicker": "oiYQhW_previewPicker",
7996
8307
  "group": "oiYQhW_group",
7997
- "quietInline": "oiYQhW_quietInline",
7998
- "diffBlock": "oiYQhW_diffBlock",
7999
- "taskDisclosure": "oiYQhW_taskDisclosure",
8000
- "groupTitle": "oiYQhW_groupTitle",
8001
- "fileRow": "oiYQhW_fileRow",
8002
- "commitMessage": "oiYQhW_commitMessage",
8003
- "commitRow": "oiYQhW_commitRow",
8004
- "crumb": "oiYQhW_crumb",
8005
8308
  "filterBar": "oiYQhW_filterBar",
8006
- "fileSize": "oiYQhW_fileSize",
8007
- "fileBlockOpen": "oiYQhW_fileBlockOpen",
8008
- "previewHead": "oiYQhW_previewHead",
8009
- "diffAdd": "oiYQhW_diffAdd",
8010
- "diffRemove": "oiYQhW_diffRemove",
8309
+ "fileRowOpen": "oiYQhW_fileRowOpen",
8310
+ "copyButton": "oiYQhW_copyButton",
8311
+ "spacer": "oiYQhW_spacer",
8011
8312
  "filterText": "oiYQhW_filterText",
8012
- "taskLabel": "oiYQhW_taskLabel",
8013
- "taskOutput": "oiYQhW_taskOutput",
8014
- "filePath": "oiYQhW_filePath",
8015
- "previewStageShort": "oiYQhW_previewStageShort",
8016
- "commitHint": "oiYQhW_commitHint",
8313
+ "terminalTabs": "oiYQhW_terminalTabs",
8314
+ "terminalView": "oiYQhW_terminalView",
8315
+ "commitBox": "oiYQhW_commitBox",
8316
+ "panelAlert": "oiYQhW_panelAlert",
8317
+ "diffLine": "oiYQhW_diffLine",
8318
+ "diffAdd": "oiYQhW_diffAdd",
8017
8319
  "diffMeta": "oiYQhW_diffMeta",
8018
- "spacer": "oiYQhW_spacer",
8019
- "pathTail": "oiYQhW_pathTail",
8020
- "taskRow": "oiYQhW_taskRow",
8021
- "taskKind": "oiYQhW_taskKind",
8022
- "groupCount": "oiYQhW_groupCount",
8023
- "addressBar": "oiYQhW_addressBar",
8320
+ "taskStatus": "oiYQhW_taskStatus",
8321
+ "split": "oiYQhW_split",
8322
+ "groupAction": "oiYQhW_groupAction",
8323
+ "rowAction": "oiYQhW_rowAction",
8324
+ "fileBlockOpen": "oiYQhW_fileBlockOpen",
8325
+ "groupTitle": "oiYQhW_groupTitle",
8024
8326
  "previewStage": "oiYQhW_previewStage",
8025
- "previewLogs": "oiYQhW_previewLogs",
8026
- "fileLine": "oiYQhW_fileLine",
8027
- "letterA": "oiYQhW_letterA",
8028
- "letterU": "oiYQhW_letterU"
8327
+ "taskDisclosureSpacer": "oiYQhW_taskDisclosureSpacer",
8328
+ "letterU": "oiYQhW_letterU",
8329
+ "terminalText": "oiYQhW_terminalText",
8330
+ "taskRow": "oiYQhW_taskRow",
8331
+ "commitMessage": "oiYQhW_commitMessage",
8332
+ "crumb": "oiYQhW_crumb",
8333
+ "branch": "oiYQhW_branch"
8029
8334
  };
8030
8335
 
8031
8336
  //#endregion
@@ -8113,6 +8418,20 @@ function useLatest(value) {
8113
8418
  function transportMessage(reason, t) {
8114
8419
  return t("error.transport", { message: reason instanceof Error ? reason.message : String(reason) });
8115
8420
  }
8421
+ /**
8422
+ * Join a typed path against the workspace unless it is already absolute.
8423
+ *
8424
+ * The Host proves containment either way — this is not a containment check — so the join only saves
8425
+ * a person from typing a long prefix. It is deliberately string arithmetic rather than a resolution:
8426
+ * the Host is the authority on what a path means, and a browser-side `..` walk would be a second,
8427
+ * weaker copy of that rule.
8428
+ * @param workspace - the absolute workspace directory.
8429
+ * @param path - the typed path.
8430
+ * @returns the absolute candidate the Host will resolve and contain.
8431
+ */
8432
+ function absoluteIn(workspace, path) {
8433
+ return path.startsWith("/") ? path : `${workspace.replace(/\/$/u, "")}/${path}`;
8434
+ }
8116
8435
 
8117
8436
  //#endregion
8118
8437
  //#region tsbuild/client/panels/ChangesPanel.js
@@ -8425,7 +8744,7 @@ function ChangesPanel({ target, t, face }) {
8425
8744
  })
8426
8745
  ] }),
8427
8746
  status?.ok !== true && (0, react_jsx_runtime.jsx)("span", { className: Panels_module_css_default.spacer }),
8428
- status?.ok === true && write?.canPush === true && (0, react_jsx_runtime.jsx)(Button, {
8747
+ status?.ok === true && write?.canPush === true && (0, react_jsx_runtime.jsx)(Button$1, {
8429
8748
  size: "sm",
8430
8749
  variant: status.ahead > 0 ? "secondary" : "ghost",
8431
8750
  icon: (0, react_jsx_runtime.jsx)(PushGlyph, { size: 14 }),
@@ -8437,7 +8756,7 @@ function ChangesPanel({ target, t, face }) {
8437
8756
  },
8438
8757
  children: status.upstream === void 0 ? t("changes.publish") : t("changes.push")
8439
8758
  }),
8440
- (0, react_jsx_runtime.jsx)(Button, {
8759
+ (0, react_jsx_runtime.jsx)(Button$1, {
8441
8760
  size: "icon",
8442
8761
  "aria-label": t("panel.refresh"),
8443
8762
  title: t("panel.refresh"),
@@ -8479,7 +8798,7 @@ function ChangesPanel({ target, t, face }) {
8479
8798
  children: t("changes.commit.amend")
8480
8799
  }),
8481
8800
  (0, react_jsx_runtime.jsx)("span", { className: Panels_module_css_default.spacer }),
8482
- write.canDraftMessage && (0, react_jsx_runtime.jsx)(Button, {
8801
+ write.canDraftMessage && (0, react_jsx_runtime.jsx)(Button$1, {
8483
8802
  size: "sm",
8484
8803
  icon: drafting ? (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconLoadingOutline16, {}) : (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconSparkle16, {}),
8485
8804
  "aria-label": t("changes.commit.suggest"),
@@ -8488,7 +8807,7 @@ function ChangesPanel({ target, t, face }) {
8488
8807
  onClick: suggest,
8489
8808
  children: t("changes.commit.suggest")
8490
8809
  }),
8491
- (0, react_jsx_runtime.jsxs)(Button, {
8810
+ (0, react_jsx_runtime.jsxs)(Button$1, {
8492
8811
  variant: "default",
8493
8812
  size: "sm",
8494
8813
  disabled: writing || drafting || message.trim() === "" || stagedCount === 0 && !amend,
@@ -8538,7 +8857,7 @@ function ChangesPanel({ target, t, face }) {
8538
8857
  className: Panels_module_css_default.groupCount,
8539
8858
  children: rows.length
8540
8859
  }),
8541
- write?.canStage === true && group !== "conflicted" && (0, react_jsx_runtime.jsx)(Button, {
8860
+ write?.canStage === true && group !== "conflicted" && (0, react_jsx_runtime.jsx)(Button$1, {
8542
8861
  size: "sm",
8543
8862
  className: Panels_module_css_default.groupAction,
8544
8863
  disabled: writing,
@@ -8575,7 +8894,7 @@ function ChangesPanel({ target, t, face }) {
8575
8894
  value: change.oldPath === void 0 ? change.path : `${change.oldPath} → ${change.path}`
8576
8895
  })
8577
8896
  ]
8578
- }), write?.canStage === true && group !== "conflicted" && (0, react_jsx_runtime.jsx)(Button, {
8897
+ }), write?.canStage === true && group !== "conflicted" && (0, react_jsx_runtime.jsx)(Button$1, {
8579
8898
  size: "icon",
8580
8899
  className: Panels_module_css_default.rowAction,
8581
8900
  "aria-label": group === "staged" ? t("changes.unstage") : t("changes.stage"),
@@ -8589,7 +8908,7 @@ function ChangesPanel({ target, t, face }) {
8589
8908
  })]
8590
8909
  }), open && (0, react_jsx_runtime.jsxs)("div", {
8591
8910
  className: Panels_module_css_default.diffBlock,
8592
- children: [state?.result?.ok === true && !state.result.binary && state.result.patch !== "" && (0, react_jsx_runtime.jsx)(Button, {
8911
+ children: [state?.result?.ok === true && !state.result.binary && state.result.patch !== "" && (0, react_jsx_runtime.jsx)(Button$1, {
8593
8912
  size: "sm",
8594
8913
  className: Panels_module_css_default.copyButton,
8595
8914
  icon: (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconCopyOutline16, {}),
@@ -8690,7 +9009,7 @@ function FilesPanel({ target, t, face }) {
8690
9009
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
8691
9010
  className: Panels_module_css_default.toolbar,
8692
9011
  children: [
8693
- (0, react_jsx_runtime.jsx)(Button, {
9012
+ (0, react_jsx_runtime.jsx)(Button$1, {
8694
9013
  size: "icon",
8695
9014
  "aria-label": t("files.up"),
8696
9015
  title: t("files.up"),
@@ -8705,7 +9024,7 @@ function FilesPanel({ target, t, face }) {
8705
9024
  value: level?.path ?? path ?? ""
8706
9025
  }),
8707
9026
  (0, react_jsx_runtime.jsx)("span", { className: Panels_module_css_default.spacer }),
8708
- (0, react_jsx_runtime.jsx)(Button, {
9027
+ (0, react_jsx_runtime.jsx)(Button$1, {
8709
9028
  size: "icon",
8710
9029
  "aria-label": t("panel.refresh"),
8711
9030
  title: t("panel.refresh"),
@@ -8779,7 +9098,7 @@ function FilesPanel({ target, t, face }) {
8779
9098
  children: [(0, react_jsx_runtime.jsx)(PathText, {
8780
9099
  className: Panels_module_css_default.filePath,
8781
9100
  value: selected
8782
- }), (0, react_jsx_runtime.jsx)(Button, {
9101
+ }), (0, react_jsx_runtime.jsx)(Button$1, {
8783
9102
  size: "icon",
8784
9103
  "aria-label": t("files.open"),
8785
9104
  title: t("files.open"),
@@ -8864,6 +9183,124 @@ function useCapabilityView(describe$2, enabled = true) {
8864
9183
  };
8865
9184
  }
8866
9185
 
9186
+ //#endregion
9187
+ //#region tsbuild/host/preview-content.js
9188
+ /**
9189
+ * The scratchpad route derived from the file route.
9190
+ *
9191
+ * The two differ only in their last segment, and a deployment that overrides one would have to
9192
+ * override the other; deriving it is what makes that impossible to forget.
9193
+ * @param fileRoute - the file route, `/…/preview-file`.
9194
+ * @returns the scratchpad route.
9195
+ */
9196
+ function scratchRoute(fileRoute) {
9197
+ return fileRoute.replace(/preview-file$/u, "preview-scratchpad");
9198
+ }
9199
+ /**
9200
+ * Reject anything that is not plain HTTP(S).
9201
+ *
9202
+ * A `file:` or `data:` URL handed to the proxy would read the Host's own disk, and a `javascript:`
9203
+ * one would be an injection; none of them is something a preview of a dev server needs.
9204
+ * @param value - the candidate URL.
9205
+ * @returns the parsed URL, or the reason it was refused.
9206
+ */
9207
+ function parseHttpUrl(value) {
9208
+ let url;
9209
+ try {
9210
+ url = new URL(value);
9211
+ } catch {
9212
+ return {
9213
+ ok: false,
9214
+ message: `${JSON.stringify(value)} is not an absolute URL`
9215
+ };
9216
+ }
9217
+ if (url.protocol !== "http:" && url.protocol !== "https:") return {
9218
+ ok: false,
9219
+ message: `only http and https can be previewed (got ${url.protocol})`
9220
+ };
9221
+ return {
9222
+ ok: true,
9223
+ url
9224
+ };
9225
+ }
9226
+ /**
9227
+ * Whether a parsed URL points at this machine.
9228
+ *
9229
+ * The proxy exists so a loopback dev server can be framed same-origin. Without this check it would
9230
+ * also fetch `http://10.0.0.5/admin` on the operator's behalf, from the operator's network position
9231
+ * — an open proxy bolted to the GUI. Only literal loopback names and addresses pass: `localhost`,
9232
+ * `127.0.0.0/8`, and `[::1]`.
9233
+ *
9234
+ * A hostname that merely *resolves* to loopback (a split-horizon DNS entry, a hostfile alias) is
9235
+ * refused rather than probed. Deciding this by lookup would make the answer depend on the resolver
9236
+ * at request time, and a DNS rebinding attack is exactly the case where the answer changes between
9237
+ * the check and the fetch.
9238
+ * @param url - a parsed URL.
9239
+ * @returns true when the host is a loopback literal.
9240
+ */
9241
+ function isLoopbackHost(url) {
9242
+ const host = url.hostname.toLowerCase().replace(/^\[|\]$/gu, "");
9243
+ if (host === "localhost" || host === "::1") return true;
9244
+ const parts = host.split(".");
9245
+ if (parts.length !== 4) return false;
9246
+ if (parts.some((part) => !/^\d{1,3}$/u.test(part))) return false;
9247
+ const [first, second] = parts.map((part) => Number.parseInt(part, 10));
9248
+ if (first !== 127) return false;
9249
+ return second !== void 0 && second >= 0 && second <= 255;
9250
+ }
9251
+ /**
9252
+ * Refuse a URL this plugin will not fetch.
9253
+ * @param value - the candidate URL.
9254
+ * @returns the parsed URL, or the reason it was refused.
9255
+ */
9256
+ function validateProxyTarget(value) {
9257
+ const parsed = parseHttpUrl(value);
9258
+ if (!parsed.ok) return parsed;
9259
+ if (!isLoopbackHost(parsed.url)) return {
9260
+ ok: false,
9261
+ message: `the preview proxy refuses ${parsed.url.hostname}: only this machine's own loopback dev servers are proxied, so the GUI cannot become an open proxy`
9262
+ };
9263
+ return parsed;
9264
+ }
9265
+ /**
9266
+ * Percent-encode a value for a query string, using the one encoder every runtime here has.
9267
+ * @param value - the raw value.
9268
+ * @returns the encoded value.
9269
+ */
9270
+ function encodeQuery(value) {
9271
+ return encodeURIComponent(value);
9272
+ }
9273
+ /**
9274
+ * Build the same-origin URL that proxies one absolute upstream URL.
9275
+ * @param proxyRoute - the absolute proxy route path, no trailing slash.
9276
+ * @param target - the loopback URL to fetch.
9277
+ * @returns the path plus query string.
9278
+ */
9279
+ function proxyUrlFor(proxyRoute, target) {
9280
+ return `${proxyRoute}?url=${encodeQuery(target)}`;
9281
+ }
9282
+ /**
9283
+ * Turn one absolute upstream URL into a same-origin frame URL when it is a loopback target.
9284
+ *
9285
+ * A cross-origin dev server is left exactly as it is: pointing the GUI's own proxy at a host it
9286
+ * would refuse is not an improvement, and the panel says why the frame is opaque rather than
9287
+ * silently refusing to show it.
9288
+ * @param proxyRoute - the absolute proxy route path, no trailing slash.
9289
+ * @param raw - the URL a person typed.
9290
+ * @returns the frame URL, and whether it is same-origin with the GUI.
9291
+ */
9292
+ function frameUrlFor(proxyRoute, raw) {
9293
+ const target = validateProxyTarget(raw);
9294
+ if (!target.ok) return {
9295
+ src: raw,
9296
+ sameOrigin: false
9297
+ };
9298
+ return {
9299
+ src: proxyUrlFor(proxyRoute, target.url.href),
9300
+ sameOrigin: true
9301
+ };
9302
+ }
9303
+
8867
9304
  //#endregion
8868
9305
  //#region tsbuild/client/terminal-screen.js
8869
9306
  /**
@@ -9093,90 +9530,1154 @@ var TerminalScreen = class {
9093
9530
  };
9094
9531
 
9095
9532
  //#endregion
9096
- //#region tsbuild/client/panels/PreviewPanel.js
9097
- /** How often the panel asks for logs and state while a server is starting. */
9098
- const FAST_POLL_MS = 400;
9099
- /** How often it asks once the server is ready and only the log view is watching. */
9100
- const SLOW_POLL_MS = 1500;
9101
- /** Retained log lines. */
9102
- const LOG_LINES = 4e3;
9103
- /** The viewport sizes the frame can be pinned to, in the order the picker lists them. */
9104
- const DEVICES = [
9105
- {
9106
- id: "desktop",
9107
- width: 0,
9108
- height: 0
9109
- },
9110
- {
9111
- id: "tablet",
9112
- width: 768,
9113
- height: 1024
9114
- },
9115
- {
9116
- id: "mobile",
9117
- width: 375,
9118
- height: 812
9533
+ //#region tsbuild/client/preview-values.js
9534
+ /**
9535
+ * How a value that crossed the frame boundary is turned into text a model can read.
9536
+ *
9537
+ * Everything the agent channel reports — a console argument, an `eval` result, an element — arrived
9538
+ * from a page nobody controls. A page can hold a cyclic object, a `BigInt`, a getter that throws, a
9539
+ * function, a DOM node, or an `Error`, and `JSON.stringify` refuses three of those outright. Each is
9540
+ * projected to something readable rather than failing the command, because "a model asked for
9541
+ * something awkward" is an ordinary event and an unexplained tool failure is not.
9542
+ *
9543
+ * Pure and frame-free, so the whole projection is stated in tests without a document.
9544
+ * @module @achasoft/dsh-advanced-sidebar/client/preview-values
9545
+ */
9546
+ /** Largest text one nested value contributes before it is cut. */
9547
+ const TEXT_CAP$1 = 400;
9548
+ /** Largest JSON body one `eval` result may produce. */
9549
+ const EVAL_CAP = 64 * 1024;
9550
+ /**
9551
+ * Render one console argument the way a browser's own console would read it.
9552
+ * @param value - the argument.
9553
+ * @returns a string.
9554
+ */
9555
+ function describeValue(value) {
9556
+ if (typeof value === "string") return value;
9557
+ if (value === null || value === void 0) return String(value);
9558
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
9559
+ if (value instanceof Error) return `${value.name}: ${value.message}`;
9560
+ if (typeof value === "function") return `[Function ${value.name === "" ? "anonymous" : value.name}]`;
9561
+ if (typeof value === "object") {
9562
+ const element = value;
9563
+ if (typeof element.outerHTML === "string") return element.outerHTML.slice(0, TEXT_CAP$1);
9564
+ try {
9565
+ return stringify(value) ?? String(value);
9566
+ } catch {
9567
+ return String(value);
9568
+ }
9119
9569
  }
9120
- ];
9570
+ return String(value);
9571
+ }
9121
9572
  /**
9122
- * Status marker for one server state.
9573
+ * Serialize a value with cycles broken and DOM nodes projected to their markup.
9574
+ * @param value - the value.
9575
+ * @returns the JSON text, or undefined when the value serializes to `undefined`.
9576
+ */
9577
+ function stringify(value) {
9578
+ return JSON.stringify(value, createReplacer());
9579
+ }
9580
+ /**
9581
+ * Build a replacer that keeps one reference per object, so a cycle serializes instead of throwing.
9123
9582
  *
9124
- * `stopped` has no marker of its own: the dot set carries no neutral member, and a `warning` dot on
9125
- * a server nobody started would read as something being wrong.
9126
- * @param state - the server's lifecycle state.
9127
- * @returns the dot state, or undefined while nothing is running.
9583
+ * A fresh replacer per call, because the seen-set is per serialization: sharing one across calls
9584
+ * would label a value `[circular]` only because an earlier, unrelated call had already seen it.
9585
+ * @returns the replacer.
9128
9586
  */
9129
- function dotState$1(state) {
9130
- switch (state) {
9131
- case "ready": return "done";
9132
- case "starting": return "ongoing";
9133
- case "failed": return "error";
9134
- case "exited": return "warning";
9135
- default: return;
9587
+ function createReplacer() {
9588
+ const seen = /* @__PURE__ */ new WeakSet();
9589
+ return (_key, value) => {
9590
+ if (typeof value === "bigint") return `${String(value)}n`;
9591
+ if (typeof value === "function") return `[Function ${value.name === "" ? "anonymous" : value.name}]`;
9592
+ if (value instanceof Error) return `${value.name}: ${value.message}`;
9593
+ if (typeof value === "object" && value !== null) {
9594
+ if (seen.has(value)) return "[circular]";
9595
+ seen.add(value);
9596
+ const element = value;
9597
+ if (typeof element.outerHTML === "string") return element.outerHTML.slice(0, TEXT_CAP$1);
9598
+ }
9599
+ return value;
9600
+ };
9601
+ }
9602
+ /**
9603
+ * Serialize a value the way a model can read it.
9604
+ * @param value - the evaluated value.
9605
+ * @returns the JSON text, and why it is not JSON when it is not.
9606
+ */
9607
+ function safeJson(value) {
9608
+ try {
9609
+ return { text: stringify(value) ?? "null" };
9610
+ } catch (error) {
9611
+ return {
9612
+ text: JSON.stringify(String(value)) ?? "null",
9613
+ note: `the value is not JSON (${error instanceof Error ? error.message : String(error)}); it was rendered with String()`
9614
+ };
9136
9615
  }
9137
9616
  }
9617
+
9618
+ //#endregion
9619
+ //#region tsbuild/client/preview-driver.js
9620
+ /** How often the panel asks for work while a preview is mounted. */
9621
+ const POLL_MS$1 = 600;
9622
+ /** How often it asks while the panel is open but nothing is framed. */
9623
+ const IDLE_POLL_MS = 2e3;
9624
+ /** Largest number of elements one `dom` walk returns. */
9625
+ const DOM_NODE_CAP = 400;
9626
+ /** Largest text length one node's own text, or the root's `innerText`, contributes. */
9627
+ const TEXT_CAP = 400;
9628
+ /** Console entries retained in the browser before the oldest are dropped. */
9629
+ const CONSOLE_CAP = 500;
9630
+ /** Characters retained from one console line. */
9631
+ const CONSOLE_LINE_CAP = 4e3;
9138
9632
  /**
9139
- * The server picker, the frame, and the log view.
9140
- * @param props - the target, the translator, and the dock's face.
9141
- * @returns the panel body.
9142
- * @see {@link PanelProps}
9633
+ * The marker that proves the console has already been wrapped.
9634
+ *
9635
+ * A document that is navigated or reloaded gets a fresh window with no wrapper, so the check runs on
9636
+ * every poll and re-installs on the frame that replaced it. The wrapper is written with
9637
+ * `Object.defineProperty` over the original methods and keeps the originals in a closure, so a page
9638
+ * that reads `console.log.name` still sees a native function.
9143
9639
  */
9144
- function PreviewPanel({ target, t, face }) {
9145
- const { previewList, previewStart, previewStop, previewLogs } = face;
9146
- const latest = useLatest(t);
9147
- const directory = target.directory;
9148
- const [servers, setServers] = (0, react.useState)(void 0);
9149
- const [launchFile, setLaunchFile] = (0, react.useState)(void 0);
9150
- const [launchError, setLaunchError] = (0, react.useState)(void 0);
9151
- const [error, setError] = (0, react.useState)(void 0);
9152
- const [selected, setSelected] = (0, react.useState)(void 0);
9153
- const [busy, setBusy] = (0, react.useState)(false);
9154
- const [generation, setGeneration] = (0, react.useState)(0);
9155
- const [address, setAddress] = (0, react.useState)("");
9156
- const [frameKey, setFrameKey] = (0, react.useState)(0);
9157
- const [device, setDevice] = (0, react.useState)("desktop");
9158
- const [showLogs, setShowLogs] = (0, react.useState)(false);
9159
- const [logRevision, setLogRevision] = (0, react.useState)(0);
9160
- const logs = (0, react.useMemo)(() => new TerminalScreen(LOG_LINES), []);
9161
- const logOffset = (0, react.useRef)(0);
9162
- const stageRef = (0, react.useRef)(null);
9163
- /** The server whose failure already opened the log view; a failed start opens it once, not per poll. */
9164
- const openedOnFailure = (0, react.useRef)(void 0);
9165
- const logViewRef = (0, react.useRef)(null);
9166
- const [stage, setStage] = (0, react.useState)({
9167
- width: 0,
9168
- height: 0
9169
- });
9170
- (0, react.useEffect)(() => {
9171
- if (directory === void 0) return;
9172
- const controller = new AbortController();
9173
- setError(void 0);
9174
- previewList(directory, controller.signal).then((result) => {
9175
- if (controller.signal.aborted) return;
9176
- if (!result.ok) {
9177
- setError(result.message);
9178
- return;
9179
- }
9640
+ const HOOK_KEY = "__dshAdvancedSidebarConsole";
9641
+ /**
9642
+ * The polling driver. One instance per mounted panel; `stop()` releases it.
9643
+ */
9644
+ var PreviewDriver = class {
9645
+ face;
9646
+ clientId;
9647
+ sessionId;
9648
+ hooks;
9649
+ /** Console entries captured since the last report, oldest first. */
9650
+ buffer = [];
9651
+ /** Commands currently executing, so a poll that overlaps the previous one does not double-run. */
9652
+ running = /* @__PURE__ */ new Set();
9653
+ timer = 0;
9654
+ stopped = true;
9655
+ /**
9656
+ * @param face - the Remote face the panel was handed.
9657
+ * @param clientId - this browser tab's identity, generated once per panel mount.
9658
+ * @param sessionId - the session the panel serves.
9659
+ * @param hooks - how to read and act on the frame.
9660
+ */
9661
+ constructor(face, clientId, sessionId, hooks) {
9662
+ this.face = face;
9663
+ this.clientId = clientId;
9664
+ this.sessionId = sessionId;
9665
+ this.hooks = hooks;
9666
+ }
9667
+ /**
9668
+ * Start polling. Idempotent, so a re-render may call it again freely.
9669
+ * @param bind - the panel's current state, refreshed on every poll.
9670
+ */
9671
+ start(bind) {
9672
+ if (!this.stopped) return;
9673
+ this.stopped = false;
9674
+ const tick = async () => {
9675
+ if (this.stopped) return;
9676
+ let cadence = this.buffer.length > 0 || this.running.size > 0 ? POLL_MS$1 : IDLE_POLL_MS;
9677
+ try {
9678
+ const state = bind();
9679
+ this.captureConsole();
9680
+ const answer = await this.face.previewPoll({
9681
+ clientId: this.clientId,
9682
+ sessionId: this.sessionId,
9683
+ mounted: state.mounted,
9684
+ bind: {
9685
+ clientId: this.clientId,
9686
+ sessionId: this.sessionId,
9687
+ mode: state.mode,
9688
+ ...state.filePath === void 0 ? {} : { filePath: state.filePath },
9689
+ ...state.workspacePath === void 0 ? {} : { workspacePath: state.workspacePath },
9690
+ ...state.url === void 0 ? {} : { url: state.url },
9691
+ inspectable: state.inspectable,
9692
+ width: state.width,
9693
+ height: state.height
9694
+ }
9695
+ });
9696
+ if (!answer.ok) cadence = IDLE_POLL_MS;
9697
+ else {
9698
+ for (const control of answer.message.controls) this.hooks.control(control);
9699
+ if (answer.message.commands.length > 0) cadence = POLL_MS$1;
9700
+ for (const command of answer.message.commands) this.execute(command);
9701
+ }
9702
+ } catch {
9703
+ cadence = IDLE_POLL_MS;
9704
+ }
9705
+ if (!this.stopped) this.timer = window.setTimeout(() => {
9706
+ tick();
9707
+ }, cadence);
9708
+ };
9709
+ tick();
9710
+ }
9711
+ /** Stop polling. Called when the panel unmounts. */
9712
+ stop() {
9713
+ this.stopped = true;
9714
+ window.clearTimeout(this.timer);
9715
+ this.timer = 0;
9716
+ }
9717
+ /**
9718
+ * Execute one command and report what it did.
9719
+ * @param command - the command.
9720
+ */
9721
+ async execute(command) {
9722
+ if (this.running.has(command.id)) return;
9723
+ this.running.add(command.id);
9724
+ let outcome;
9725
+ try {
9726
+ outcome = await this.run(command);
9727
+ } catch (error) {
9728
+ outcome = {
9729
+ ok: false,
9730
+ error: error instanceof Error ? error.message : String(error)
9731
+ };
9732
+ }
9733
+ this.running.delete(command.id);
9734
+ const console_ = this.drain();
9735
+ try {
9736
+ await this.face.previewResult({
9737
+ clientId: this.clientId,
9738
+ id: command.id,
9739
+ ok: outcome.ok,
9740
+ ...outcome.ok ? { result: outcome.result } : { error: outcome.error },
9741
+ ...console_.length === 0 ? {} : { console: console_ }
9742
+ });
9743
+ } catch {}
9744
+ }
9745
+ /**
9746
+ * Run one command against the frame.
9747
+ * @param command - the command.
9748
+ * @returns the result, or the sentence explaining the refusal.
9749
+ */
9750
+ async run(command) {
9751
+ if (command.kind === "open") {
9752
+ const frame$1 = this.hooks.frame();
9753
+ return {
9754
+ ok: true,
9755
+ result: {
9756
+ kind: "ack",
9757
+ detail: frame$1.element === null ? "the Preview panel is open and has taken the request" : `the Preview panel is loading ${frame$1.element.src === "" ? "the requested document" : shortUrl(frame$1.element.src)}`
9758
+ }
9759
+ };
9760
+ }
9761
+ if (command.kind === "reload") {
9762
+ this.hooks.reload();
9763
+ return {
9764
+ ok: true,
9765
+ result: {
9766
+ kind: "ack",
9767
+ detail: "the frame was reloaded"
9768
+ }
9769
+ };
9770
+ }
9771
+ if (command.kind === "resize") {
9772
+ const width = command.width ?? 0;
9773
+ const height = command.height ?? 0;
9774
+ this.hooks.resize(width, height);
9775
+ return {
9776
+ ok: true,
9777
+ result: {
9778
+ kind: "ack",
9779
+ detail: `the frame viewport is now ${String(width)}×${String(height)}`,
9780
+ width,
9781
+ height
9782
+ }
9783
+ };
9784
+ }
9785
+ if (command.kind === "close") return {
9786
+ ok: true,
9787
+ result: {
9788
+ kind: "ack",
9789
+ detail: "the preview was closed"
9790
+ }
9791
+ };
9792
+ if (command.kind === "console") {
9793
+ const drained = this.drain();
9794
+ const cursor = command.cursor ?? 0;
9795
+ const entries = drained.map((entry) => ({
9796
+ level: entry.level,
9797
+ text: entry.text,
9798
+ at: entry.at
9799
+ }));
9800
+ return {
9801
+ ok: true,
9802
+ result: {
9803
+ kind: "console",
9804
+ entries,
9805
+ cursor: cursor + entries.length,
9806
+ lossy: false
9807
+ }
9808
+ };
9809
+ }
9810
+ const frame = this.hooks.frame();
9811
+ if (frame.element === null) return {
9812
+ ok: false,
9813
+ error: "no preview is mounted in the panel, so there is nothing to inspect"
9814
+ };
9815
+ if (frame.document === null || frame.window === null) return {
9816
+ ok: false,
9817
+ error: "the framed page is not same-origin with this GUI, so its document cannot be read. Open a loopback URL (the Host proxies it) or a workspace file to make it inspectable."
9818
+ };
9819
+ switch (command.kind) {
9820
+ case "dom": return {
9821
+ ok: true,
9822
+ result: readDom(frame, command.selector ?? "")
9823
+ };
9824
+ case "eval": return {
9825
+ ok: true,
9826
+ result: evaluate(frame, command.expression ?? "")
9827
+ };
9828
+ case "click": return click(frame, command.selector ?? "");
9829
+ case "input": return input(frame, command);
9830
+ default: return {
9831
+ ok: false,
9832
+ error: `the panel does not know how to ${String(command.kind)}`
9833
+ };
9834
+ }
9835
+ }
9836
+ /**
9837
+ * Take everything captured since the last drain.
9838
+ * @returns the entries, oldest first.
9839
+ */
9840
+ drain() {
9841
+ return this.buffer.splice(0, this.buffer.length);
9842
+ }
9843
+ /**
9844
+ * Wrap the frame's console, once per document.
9845
+ *
9846
+ * Called from the poll rather than from a load listener because a navigation can complete between
9847
+ * two polls, and the check is one property read on the frame's own window.
9848
+ */
9849
+ captureConsole() {
9850
+ const win = this.hooks.frame().window;
9851
+ if (win === null) return;
9852
+ const globals = win;
9853
+ const carrier = globals;
9854
+ if (carrier[HOOK_KEY] !== void 0) return;
9855
+ const record = (level, parts) => {
9856
+ this.push({
9857
+ level,
9858
+ text: parts.map(describeValue).join(" "),
9859
+ at: Date.now()
9860
+ });
9861
+ };
9862
+ try {
9863
+ carrier[HOOK_KEY] = true;
9864
+ const target = globals.console;
9865
+ const original = {
9866
+ log: target.log.bind(target),
9867
+ info: target.info.bind(target),
9868
+ warn: target.warn.bind(target),
9869
+ error: target.error.bind(target)
9870
+ };
9871
+ for (const level of [
9872
+ "log",
9873
+ "info",
9874
+ "warn",
9875
+ "error"
9876
+ ]) Object.defineProperty(target, level, {
9877
+ configurable: true,
9878
+ writable: true,
9879
+ value: (...parts) => {
9880
+ record(level, parts);
9881
+ original[level](...parts);
9882
+ }
9883
+ });
9884
+ win.addEventListener("error", (event) => {
9885
+ const where = event.filename === "" ? "" : ` (${event.filename}:${String(event.lineno)})`;
9886
+ record("uncaught", [`${event.message}${where}`]);
9887
+ });
9888
+ win.addEventListener("unhandledrejection", (event) => {
9889
+ record("rejection", [describeValue(event.reason)]);
9890
+ });
9891
+ } catch {}
9892
+ }
9893
+ /**
9894
+ * Append one captured entry, dropping the oldest past the ring.
9895
+ * @param entry - the entry.
9896
+ */
9897
+ push(entry) {
9898
+ this.buffer.push({
9899
+ level: entry.level,
9900
+ text: entry.text.length > CONSOLE_LINE_CAP ? `${entry.text.slice(0, CONSOLE_LINE_CAP)}…` : entry.text,
9901
+ at: entry.at
9902
+ });
9903
+ while (this.buffer.length > CONSOLE_CAP) this.buffer.shift();
9904
+ }
9905
+ };
9906
+ /**
9907
+ * A short display form of a URL, for one-line answers.
9908
+ * @param value - the URL.
9909
+ * @returns the pathname and search, or the value when it is not a URL.
9910
+ */
9911
+ function shortUrl(value) {
9912
+ try {
9913
+ const url = new URL(value, window.location.origin);
9914
+ return `${url.pathname}${url.search}`;
9915
+ } catch {
9916
+ return value;
9917
+ }
9918
+ }
9919
+ /**
9920
+ * Read the rendered DOM under one selector.
9921
+ * @param frame - the frame.
9922
+ * @param selector - a CSS selector, or the empty string for the document element.
9923
+ * @returns the reading.
9924
+ */
9925
+ function readDom(frame, selector) {
9926
+ const doc = frame.document;
9927
+ const win = frame.window;
9928
+ /* v8 ignore next -- `run` refuses a null document before this is called. */
9929
+ if (doc === null || win === null) throw new Error("the frame has no readable document");
9930
+ const root = selector === "" ? doc.documentElement : doc.querySelector(selector);
9931
+ if (root === null) throw new Error(`no element matches ${JSON.stringify(selector)} in the framed document`);
9932
+ const nodes = [];
9933
+ let truncated = false;
9934
+ const walk = (element, depth) => {
9935
+ if (nodes.length >= DOM_NODE_CAP) {
9936
+ truncated = true;
9937
+ return;
9938
+ }
9939
+ const style = win.getComputedStyle(element);
9940
+ const rect = element.getBoundingClientRect();
9941
+ const own = [...element.childNodes].filter((node) => node.nodeType === 3).map((node) => node.textContent ?? "").join(" ").replace(/\s+/gu, " ").trim();
9942
+ nodes.push({
9943
+ tag: element.tagName.toLowerCase(),
9944
+ selector: selectorFragment(element),
9945
+ text: own.slice(0, TEXT_CAP),
9946
+ display: style.display,
9947
+ box: {
9948
+ x: Math.round(rect.x),
9949
+ y: Math.round(rect.y),
9950
+ width: Math.round(rect.width),
9951
+ height: Math.round(rect.height)
9952
+ },
9953
+ depth
9954
+ });
9955
+ for (const child of element.children) walk(child, depth + 1);
9956
+ };
9957
+ walk(root, 0);
9958
+ const inner = root.innerText ?? root.textContent ?? "";
9959
+ return {
9960
+ kind: "dom",
9961
+ selector,
9962
+ viewport: {
9963
+ width: win.innerWidth,
9964
+ height: win.innerHeight
9965
+ },
9966
+ nodes,
9967
+ text: inner.replace(/\s+/gu, " ").trim().slice(0, TEXT_CAP * 4),
9968
+ truncated,
9969
+ url: doc.location.href
9970
+ };
9971
+ }
9972
+ /**
9973
+ * A short, readable selector fragment for one element.
9974
+ * @param element - the element.
9975
+ * @returns `#id.class.class`, or the empty string when the element has neither.
9976
+ */
9977
+ function selectorFragment(element) {
9978
+ return `${element.id === "" ? "" : `#${element.id}`}${typeof element.className === "string" && element.className.trim() !== "" ? `.${element.className.trim().split(/\s+/u).slice(0, 3).join(".")}` : ""}`.slice(0, 120);
9979
+ }
9980
+ /**
9981
+ * Evaluate one expression inside the frame and serialize its value.
9982
+ * @param frame - the frame.
9983
+ * @param expression - the source.
9984
+ * @returns the value as JSON text, with a note when JSON could not represent it.
9985
+ */
9986
+ function evaluate(frame, expression) {
9987
+ const win = frame.window;
9988
+ /* v8 ignore next -- `run` refuses a null window before this is called. */
9989
+ if (win === null) throw new Error("the frame has no readable window");
9990
+ const source = expression.trim();
9991
+ if (source === "") throw new Error("the expression is empty");
9992
+ const construct = win.Function;
9993
+ if (construct === void 0) throw new Error("the framed page has no Function constructor to evaluate with");
9994
+ const evaluate$1 = (code) => new construct(code)();
9995
+ let value;
9996
+ try {
9997
+ value = evaluate$1(`return (${source})`);
9998
+ } catch (error) {
9999
+ if (error instanceof SyntaxError) value = evaluate$1(source);
10000
+ else throw new Error(error instanceof Error ? `${error.name}: ${error.message}` : String(error));
10001
+ }
10002
+ const json = safeJson(value);
10003
+ return {
10004
+ kind: "eval",
10005
+ value: json.text.length > EVAL_CAP ? `${json.text.slice(0, EVAL_CAP)}…` : json.text,
10006
+ ...json.note === void 0 ? {} : { note: json.note },
10007
+ truncated: json.text.length > EVAL_CAP
10008
+ };
10009
+ }
10010
+ /**
10011
+ * Dispatch a real click on one element.
10012
+ * @param frame - the frame.
10013
+ * @param selector - the CSS selector.
10014
+ * @returns the acknowledgement, or the refusal.
10015
+ */
10016
+ function click(frame, selector) {
10017
+ const doc = frame.document;
10018
+ /* v8 ignore next -- `run` refuses a null document before this is called. */
10019
+ if (doc === null) return {
10020
+ ok: false,
10021
+ error: "the frame has no readable document"
10022
+ };
10023
+ if (selector === "") return {
10024
+ ok: false,
10025
+ error: "a click needs a CSS selector"
10026
+ };
10027
+ const element = doc.querySelector(selector);
10028
+ if (element === null) return {
10029
+ ok: false,
10030
+ error: `no element matches ${JSON.stringify(selector)}`
10031
+ };
10032
+ if (!(element instanceof HTMLElement)) return {
10033
+ ok: false,
10034
+ error: `${JSON.stringify(selector)} is not an element this can click`
10035
+ };
10036
+ element.click();
10037
+ return {
10038
+ ok: true,
10039
+ result: {
10040
+ kind: "ack",
10041
+ detail: `clicked ${selectorFragment(element) === "" ? element.tagName.toLowerCase() : selectorFragment(element)}`
10042
+ }
10043
+ };
10044
+ }
10045
+ /**
10046
+ * Set one field's value and dispatch the events a person's typing would.
10047
+ * @param frame - the frame.
10048
+ * @param command - the command carrying the selector, the text, and an optional key.
10049
+ * @returns the acknowledgement, or the refusal.
10050
+ */
10051
+ function input(frame, command) {
10052
+ const doc = frame.document;
10053
+ /* v8 ignore next -- `run` refuses a null document before this is called. */
10054
+ if (doc === null) return {
10055
+ ok: false,
10056
+ error: "the frame has no readable document"
10057
+ };
10058
+ const selector = command.selector ?? "";
10059
+ if (selector === "") return {
10060
+ ok: false,
10061
+ error: "typing needs a CSS selector"
10062
+ };
10063
+ const element = doc.querySelector(selector);
10064
+ if (element === null) return {
10065
+ ok: false,
10066
+ error: `no element matches ${JSON.stringify(selector)}`
10067
+ };
10068
+ if (!(element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement)) return {
10069
+ ok: false,
10070
+ error: `${JSON.stringify(selector)} is a <${element.tagName.toLowerCase()}>, which has no value to set`
10071
+ };
10072
+ const text = command.text ?? "";
10073
+ const prototype = element instanceof HTMLTextAreaElement ? HTMLTextAreaElement.prototype : element instanceof HTMLSelectElement ? HTMLSelectElement.prototype : HTMLInputElement.prototype;
10074
+ const setter = Object.getOwnPropertyDescriptor(prototype, "value")?.set;
10075
+ if (setter === void 0) element.value = text;
10076
+ else setter.call(element, text);
10077
+ element.dispatchEvent(new Event("input", { bubbles: true }));
10078
+ element.dispatchEvent(new Event("change", { bubbles: true }));
10079
+ if (command.key !== void 0 && command.key !== "") {
10080
+ const init = {
10081
+ key: command.key,
10082
+ code: command.key,
10083
+ bubbles: true,
10084
+ cancelable: true
10085
+ };
10086
+ element.dispatchEvent(new KeyboardEvent("keydown", init));
10087
+ element.dispatchEvent(new KeyboardEvent("keyup", init));
10088
+ if (command.key === "Enter" && element instanceof HTMLInputElement) element.form?.requestSubmit();
10089
+ }
10090
+ return {
10091
+ ok: true,
10092
+ result: {
10093
+ kind: "ack",
10094
+ detail: `set ${selectorFragment(element) === "" ? element.tagName.toLowerCase() : selectorFragment(element)} to ${JSON.stringify(text)}${command.key === void 0 ? "" : ` and pressed ${command.key}`}`
10095
+ }
10096
+ };
10097
+ }
10098
+
10099
+ //#endregion
10100
+ //#region \0dsh-css:/Users/aslan_nejad/Desktop/DEV/achasoft/dsh-plugins/dsh-advanced-sidebar/src/client/panels/Preview.module.css.mjs
10101
+ const css$4 = ".wttZHa_modes{flex:none}.wttZHa_toolbar{border-bottom:1px solid var(--dsw-alias-border-l2);flex:none;align-items:center;gap:6px;padding:6px 8px;display:flex}.wttZHa_grow{flex:1;min-width:0}.wttZHa_quiet{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;flex:none;margin:0;padding:4px 10px;font-size:11px;line-height:16px}.wttZHa_note{flex:none;margin:4px 8px}.wttZHa_split{flex-direction:column;flex:1;min-height:0;display:flex}.wttZHa_scratchPane{border-bottom:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;gap:4px;padding:0 8px 6px;display:flex}.wttZHa_scratchText{resize:vertical;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);width:100%;min-height:120px;max-height:40vh;color:var(--dsw-alias-label-primary);font-family:var(--ds-font-family-code);tab-size:2;border-radius:6px;padding:8px;font-size:11px;line-height:16px}.wttZHa_scratchText:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}.wttZHa_markdownPane{z-index:1;background:var(--dsw-alias-bg-base);flex:1;min-height:0;padding:12px 14px 20px;position:relative;overflow:auto}.wttZHa_media{object-fit:contain;background:var(--dsw-alias-bg-base);max-width:100%;max-height:100%}.wttZHa_pdfPane{background:var(--dsw-alias-bg-base);border:0;flex:1;width:100%;min-height:0}.wttZHa_empty{color:var(--dsw-alias-label-tertiary);text-align:center;flex-direction:column;flex:1;justify-content:center;align-items:center;gap:8px;padding:16px 20px;font-size:12px;display:flex}.wttZHa_emptyActions{gap:6px;display:flex}.wttZHa_viewportBar{border-bottom:0;border-top:1px solid var(--dsw-alias-border-l2)}.wttZHa_frameUnder{visibility:hidden;width:0;height:0;position:absolute}.wttZHa_stageHost{position:relative}";
10102
+ const tagId$4 = "@achasoft/dsh-advanced-sidebar/Preview.module.css";
10103
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
10104
+ const tag = document.createElement("style");
10105
+ tag.dataset.plugin = "@achasoft/dsh-advanced-sidebar";
10106
+ tag.dataset.pluginCss = tagId$4;
10107
+ tag.textContent = css$4;
10108
+ document.head.appendChild(tag);
10109
+ }
10110
+ var Preview_module_css_default = {
10111
+ "modes": "wttZHa_modes",
10112
+ "note": "wttZHa_note",
10113
+ "markdownPane": "wttZHa_markdownPane",
10114
+ "pdfPane": "wttZHa_pdfPane",
10115
+ "split": "wttZHa_split",
10116
+ "emptyActions": "wttZHa_emptyActions",
10117
+ "stageHost": "wttZHa_stageHost",
10118
+ "quiet": "wttZHa_quiet",
10119
+ "scratchText": "wttZHa_scratchText",
10120
+ "frameUnder": "wttZHa_frameUnder",
10121
+ "scratchPane": "wttZHa_scratchPane",
10122
+ "grow": "wttZHa_grow",
10123
+ "viewportBar": "wttZHa_viewportBar",
10124
+ "empty": "wttZHa_empty",
10125
+ "toolbar": "wttZHa_toolbar",
10126
+ "media": "wttZHa_media"
10127
+ };
10128
+
10129
+ //#endregion
10130
+ //#region tsbuild/client/panels/preview-file.js
10131
+ /** How often the previewed file's token is re-read while a file is open. */
10132
+ const TOKEN_POLL_MS = 900;
10133
+ /**
10134
+ * Read one file's description, contained to the workspace by the Host.
10135
+ *
10136
+ * The workspace is sent with the path and the Host proves containment, so a mistyped absolute path
10137
+ * is refused by the same check the Files panel uses rather than by a string comparison here.
10138
+ * @param face - the dock's face.
10139
+ * @param workspace - the workspace the path must stay inside.
10140
+ * @param path - the file, absolute or relative.
10141
+ * @param signal - cancellation for the read.
10142
+ * @returns the description, or a failure.
10143
+ */
10144
+ async function loadFileInfo(face, workspace, path, signal) {
10145
+ const result = await face.previewFileInfo(workspace, path, signal);
10146
+ if (!result.ok) return { error: result.message };
10147
+ return result;
10148
+ }
10149
+ /**
10150
+ * Re-read one open file's token and report when it moved.
10151
+ * @param face - the dock's face.
10152
+ * @param workspace - the workspace.
10153
+ * @param path - the file on screen, or undefined to watch nothing.
10154
+ * @param onInfo - called with every successful reading.
10155
+ * @param onChanged - called when the file's token moved.
10156
+ */
10157
+ function useFileWatch(face, workspace, path, onInfo, onChanged) {
10158
+ const latest = (0, react.useRef)({
10159
+ onInfo,
10160
+ onChanged
10161
+ });
10162
+ latest.current = {
10163
+ onInfo,
10164
+ onChanged
10165
+ };
10166
+ const token = (0, react.useRef)(void 0);
10167
+ (0, react.useEffect)(() => {
10168
+ token.current = void 0;
10169
+ if (workspace === void 0 || path === void 0 || path === "") return;
10170
+ let live = true;
10171
+ const timer = window.setInterval(() => {
10172
+ face.previewFileInfo(workspace, path).then((result) => {
10173
+ if (!live || !result.ok) return;
10174
+ const next = result;
10175
+ latest.current.onInfo(next);
10176
+ if (token.current !== void 0 && token.current !== next.token) {
10177
+ token.current = next.token;
10178
+ latest.current.onChanged();
10179
+ } else token.current = next.token;
10180
+ }, () => {});
10181
+ }, TOKEN_POLL_MS);
10182
+ return () => {
10183
+ live = false;
10184
+ window.clearInterval(timer);
10185
+ };
10186
+ }, [
10187
+ face,
10188
+ workspace,
10189
+ path
10190
+ ]);
10191
+ }
10192
+ /**
10193
+ * The path field, the file's facts, and the manual Refresh.
10194
+ * @param props - the mode contract plus the file's state.
10195
+ * @returns the mode's controls.
10196
+ */
10197
+ function PreviewFileMode({ t, face, state, setState, workspace, info, busy, onInfo, onError }) {
10198
+ const [draft, setDraft] = (0, react.useState)(state.filePath);
10199
+ (0, react.useEffect)(() => {
10200
+ setDraft(state.filePath);
10201
+ }, [state.filePath]);
10202
+ const inspect = (0, react.useCallback)((path) => {
10203
+ if (workspace === void 0 || path === "") return;
10204
+ onError(void 0);
10205
+ loadFileInfo(face, workspace, absoluteIn(workspace, path)).then((loaded) => {
10206
+ if ("error" in loaded) {
10207
+ onInfo(void 0);
10208
+ onError(loaded.error);
10209
+ return;
10210
+ }
10211
+ onInfo(loaded);
10212
+ }, (reason) => {
10213
+ onError(transportMessage(reason, t));
10214
+ });
10215
+ }, [
10216
+ face,
10217
+ workspace,
10218
+ onInfo,
10219
+ onError,
10220
+ t
10221
+ ]);
10222
+ const open = () => {
10223
+ const path = draft.trim();
10224
+ setState({
10225
+ filePath: path,
10226
+ committed: true
10227
+ });
10228
+ inspect(path);
10229
+ };
10230
+ const kind = info?.kind;
10231
+ const framed = info?.kind === "iframe" && info.url !== void 0;
10232
+ const drawnHere = kind === "markdown" || kind === "image" || kind === "media" || kind === "pdf";
10233
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
10234
+ (0, react_jsx_runtime.jsxs)("div", {
10235
+ className: Preview_module_css_default.toolbar,
10236
+ children: [
10237
+ (0, react_jsx_runtime.jsx)(Input, {
10238
+ className: Preview_module_css_default.grow,
10239
+ code: true,
10240
+ spellCheck: false,
10241
+ autoComplete: "off",
10242
+ "aria-label": t("preview.file.field"),
10243
+ placeholder: t("preview.file.placeholder"),
10244
+ value: draft,
10245
+ onChange: (event) => {
10246
+ setDraft(event.target.value);
10247
+ },
10248
+ onKeyDown: (event) => {
10249
+ if (event.key === "Enter") open();
10250
+ }
10251
+ }),
10252
+ (0, react_jsx_runtime.jsx)(Button$1, {
10253
+ size: "sm",
10254
+ disabled: draft.trim() === "" || workspace === void 0,
10255
+ onClick: open,
10256
+ children: t("preview.file.open")
10257
+ }),
10258
+ (0, react_jsx_runtime.jsx)(Button$1, {
10259
+ size: "icon",
10260
+ "aria-label": t("panel.refresh"),
10261
+ title: t("panel.refresh"),
10262
+ disabled: info === void 0,
10263
+ onClick: () => {
10264
+ if (info !== void 0) inspect(info.path);
10265
+ },
10266
+ children: busy ? (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconLoadingOutline16, {}) : (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline14, {})
10267
+ })
10268
+ ]
10269
+ }),
10270
+ workspace === void 0 && (0, react_jsx_runtime.jsx)("p", {
10271
+ className: Preview_module_css_default.quiet,
10272
+ children: t("preview.file.noWorkspace")
10273
+ }),
10274
+ info !== void 0 && (0, react_jsx_runtime.jsxs)("p", {
10275
+ className: Preview_module_css_default.quiet,
10276
+ children: [t("preview.file.facts", {
10277
+ name: info.name,
10278
+ kind: t(`preview.kind.${kind ?? "other"}`),
10279
+ bytes: formatBytes(info.bytes)
10280
+ }), info.withinLimit ? "" : ` — ${t("preview.file.overLimit")}`]
10281
+ }),
10282
+ info !== void 0 && !framed && !drawnHere && !info.withinLimit && (0, react_jsx_runtime.jsx)(Alert, {
10283
+ tone: "default",
10284
+ className: Preview_module_css_default.note,
10285
+ children: t("preview.file.overLimit")
10286
+ }),
10287
+ info !== void 0 && !framed && !drawnHere && info.withinLimit && (0, react_jsx_runtime.jsx)(Alert, {
10288
+ tone: "default",
10289
+ className: Preview_module_css_default.note,
10290
+ children: t("preview.file.notPreviewable")
10291
+ }),
10292
+ info === void 0 && state.filePath === "" && (0, react_jsx_runtime.jsx)("p", {
10293
+ className: Preview_module_css_default.quiet,
10294
+ children: t("preview.file.empty")
10295
+ })
10296
+ ] });
10297
+ }
10298
+
10299
+ //#endregion
10300
+ //#region tsbuild/client/preview-storage.js
10301
+ /**
10302
+ * Where the Preview panel's scratchpad document lives between reloads.
10303
+ *
10304
+ * A scratchpad is a thought being worked out, not a deliverable, so it is stored in this browser
10305
+ * rather than written to the workspace as a file — and per workspace, because two projects'
10306
+ * experiments have nothing to do with each other.
10307
+ *
10308
+ * Split out of the mode component so the rules are testable without a DOM, and so every storage
10309
+ * failure is handled in one place: `localStorage` may be absent (a non-browser host), disabled
10310
+ * (private modes and hardened settings), or full, and none of those may take the panel down. Each is
10311
+ * reported as "nothing saved" or "the write was refused", which the editor renders as a note.
10312
+ * @module @achasoft/dsh-plugins/dsh-advanced-sidebar/client/preview-storage
10313
+ */
10314
+ /**
10315
+ * Largest document this mode will store.
10316
+ *
10317
+ * A person typing HTML reaches a few kilobytes; a megabyte is a paste of something that belongs in a
10318
+ * file. The Host's own route refuses more than its limit, so reading is capped here too rather than
10319
+ * discovering the refusal after a round trip.
10320
+ */
10321
+ const MAX_SCRATCHPAD_CHARS = 512 * 1024;
10322
+ /**
10323
+ * The storage key one workspace's scratchpad lives under.
10324
+ *
10325
+ * The workspace path is the whole identity: two sessions in one directory are editing the same
10326
+ * experiment, and a session with no directory shares one global scratchpad rather than losing it.
10327
+ * @param workspace - the absolute workspace path, or undefined.
10328
+ * @returns the key.
10329
+ */
10330
+ function scratchpadKey(workspace) {
10331
+ return `dsh.advancedSidebar.scratchpad:${workspace ?? ""}`;
10332
+ }
10333
+ /**
10334
+ * The browser's own storage, or undefined where there is none.
10335
+ *
10336
+ * Read through the global each time rather than captured: a test (and a hardened browser) may make
10337
+ * it appear or vanish between calls, and a captured reference to a storage that later throws is
10338
+ * exactly the failure this module exists to contain.
10339
+ * @returns the storage, or undefined.
10340
+ */
10341
+ function storage() {
10342
+ try {
10343
+ return typeof globalThis.localStorage === "undefined" ? void 0 : globalThis.localStorage;
10344
+ } catch {
10345
+ return;
10346
+ }
10347
+ }
10348
+ /**
10349
+ * Read one workspace's saved document.
10350
+ * @param workspace - the absolute workspace path.
10351
+ * @returns the saved document, or undefined when there is none or storage refuses.
10352
+ */
10353
+ function readScratchpad(workspace) {
10354
+ try {
10355
+ const saved = storage()?.getItem(scratchpadKey(workspace));
10356
+ return saved === null || saved === void 0 || saved === "" ? void 0 : saved.slice(0, MAX_SCRATCHPAD_CHARS);
10357
+ } catch {
10358
+ return;
10359
+ }
10360
+ }
10361
+ /**
10362
+ * Write one workspace's document, reporting a refused write instead of throwing.
10363
+ * @param workspace - the absolute workspace path.
10364
+ * @param text - the document.
10365
+ * @returns true when the browser accepted it.
10366
+ */
10367
+ function writeScratchpad(workspace, text) {
10368
+ const store = storage();
10369
+ if (store === void 0) return false;
10370
+ try {
10371
+ store.setItem(scratchpadKey(workspace), text.slice(0, MAX_SCRATCHPAD_CHARS));
10372
+ return true;
10373
+ } catch {
10374
+ return false;
10375
+ }
10376
+ }
10377
+
10378
+ //#endregion
10379
+ //#region tsbuild/client/panels/preview-scratchpad.js
10380
+ /** How long after the last keystroke the document is rendered and saved. */
10381
+ const RENDER_DEBOUNCE_MS = 500;
10382
+ /** The document a scratchpad starts with, so the mode opens on something that renders. */
10383
+ const SEED = [
10384
+ "<!doctype html>",
10385
+ "<html lang=\"en\">",
10386
+ " <head><meta charset=\"utf-8\"><title>Scratchpad</title></head>",
10387
+ " <body>",
10388
+ " <h1>Scratchpad</h1>",
10389
+ " <p>Edit the HTML on the left; this pane re-renders as you type.</p>",
10390
+ " </body>",
10391
+ "</html>"
10392
+ ].join("\n");
10393
+ /**
10394
+ * Own the scratchpad's text, its storage, and its debounce.
10395
+ *
10396
+ * The rendered document is not this hook's business: the panel holds the frame, so the hook reports
10397
+ * the text and calls {@link onPublish} after the debounce, and the panel decides how a document
10398
+ * becomes a frame source. Keeping one owner for the frame is what makes the agent's `open` and a
10399
+ * person's keystroke land on the same state.
10400
+ * @param workspace - the workspace whose scratchpad this is.
10401
+ * @param onPublish - called with the document to render after the debounce.
10402
+ * @returns the editor's state.
10403
+ */
10404
+ function useScratchpad(workspace, onPublish) {
10405
+ const [text, setText] = (0, react.useState)(() => readScratchpad(workspace) ?? SEED);
10406
+ const [pending, setPending] = (0, react.useState)(false);
10407
+ const [unsaved, setUnsaved] = (0, react.useState)(false);
10408
+ const timer = (0, react.useRef)(0);
10409
+ const latest = (0, react.useRef)(text);
10410
+ const publish = (0, react.useRef)(onPublish);
10411
+ publish.current = onPublish;
10412
+ (0, react.useEffect)(() => {
10413
+ const next = readScratchpad(workspace) ?? SEED;
10414
+ setText(next);
10415
+ latest.current = next;
10416
+ setUnsaved(false);
10417
+ publish.current(next);
10418
+ }, [workspace]);
10419
+ const change = (0, react.useCallback)((value) => {
10420
+ const capped = value.slice(0, MAX_SCRATCHPAD_CHARS);
10421
+ setText(capped);
10422
+ latest.current = capped;
10423
+ setPending(true);
10424
+ window.clearTimeout(timer.current);
10425
+ timer.current = window.setTimeout(() => {
10426
+ setPending(false);
10427
+ setUnsaved(!writeScratchpad(workspace, capped));
10428
+ publish.current(capped);
10429
+ }, RENDER_DEBOUNCE_MS);
10430
+ }, [workspace]);
10431
+ (0, react.useEffect)(() => () => {
10432
+ window.clearTimeout(timer.current);
10433
+ }, []);
10434
+ return {
10435
+ text,
10436
+ setText: change,
10437
+ pending,
10438
+ unsaved
10439
+ };
10440
+ }
10441
+ /**
10442
+ * The editor pane, its Render button, and the storage note.
10443
+ * @param props - the mode contract plus the editor state.
10444
+ * @returns the mode's controls.
10445
+ */
10446
+ function PreviewScratchpadMode({ t, scratch }) {
10447
+ const note = (0, react.useMemo)(() => {
10448
+ if (scratch.unsaved) return t("preview.scratch.unsaved");
10449
+ if (scratch.pending) return t("preview.scratch.pending");
10450
+ return t("preview.scratch.saved");
10451
+ }, [
10452
+ scratch.pending,
10453
+ scratch.unsaved,
10454
+ t
10455
+ ]);
10456
+ return (0, react_jsx_runtime.jsxs)("div", {
10457
+ className: Preview_module_css_default.scratchPane,
10458
+ children: [
10459
+ (0, react_jsx_runtime.jsxs)("div", {
10460
+ className: Preview_module_css_default.toolbar,
10461
+ children: [(0, react_jsx_runtime.jsx)("span", { className: Preview_module_css_default.grow }), (0, react_jsx_runtime.jsx)(Button$1, {
10462
+ size: "sm",
10463
+ onClick: () => {
10464
+ scratch.setText(scratch.text);
10465
+ },
10466
+ children: t("preview.scratch.render")
10467
+ })]
10468
+ }),
10469
+ (0, react_jsx_runtime.jsx)("textarea", {
10470
+ className: Preview_module_css_default.scratchText,
10471
+ "aria-label": t("preview.scratch.editor"),
10472
+ spellCheck: false,
10473
+ value: scratch.text,
10474
+ onChange: (event) => {
10475
+ scratch.setText(event.target.value);
10476
+ }
10477
+ }),
10478
+ (0, react_jsx_runtime.jsx)("p", {
10479
+ className: Preview_module_css_default.quiet,
10480
+ children: note
10481
+ })
10482
+ ]
10483
+ });
10484
+ }
10485
+
10486
+ //#endregion
10487
+ //#region tsbuild/client/panels/preview-url.js
10488
+ /**
10489
+ * The address bar, its Go, and the cross-origin explanation.
10490
+ * @param props - the panel's mode contract.
10491
+ * @returns the mode's controls.
10492
+ */
10493
+ function PreviewUrlMode({ t, state, setState, onReload }) {
10494
+ const [draft, setDraft] = (0, react.useState)(state.url);
10495
+ (0, react.useEffect)(() => {
10496
+ setDraft(state.url);
10497
+ }, [state.url]);
10498
+ const typed = draft.trim();
10499
+ const proxied = typed !== "" && state.proxyRoute !== void 0 && frameUrlFor(state.proxyRoute, typed).sameOrigin;
10500
+ const publicUrl = typed !== "" && /^https?:\/\//iu.test(typed) && !proxied;
10501
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
10502
+ (0, react_jsx_runtime.jsxs)("div", {
10503
+ className: Preview_module_css_default.toolbar,
10504
+ children: [
10505
+ (0, react_jsx_runtime.jsx)(Input, {
10506
+ className: Preview_module_css_default.grow,
10507
+ code: true,
10508
+ spellCheck: false,
10509
+ autoComplete: "off",
10510
+ "aria-label": t("preview.url.field"),
10511
+ placeholder: t("preview.url.placeholder"),
10512
+ value: draft,
10513
+ onChange: (event) => {
10514
+ setDraft(event.target.value);
10515
+ },
10516
+ onKeyDown: (event) => {
10517
+ if (event.key === "Enter") setState({
10518
+ url: typed,
10519
+ committed: true
10520
+ });
10521
+ }
10522
+ }),
10523
+ (0, react_jsx_runtime.jsx)(Button$1, {
10524
+ size: "sm",
10525
+ disabled: typed === "",
10526
+ onClick: () => {
10527
+ setState({
10528
+ url: typed,
10529
+ committed: true
10530
+ });
10531
+ },
10532
+ children: t("preview.url.go")
10533
+ }),
10534
+ (0, react_jsx_runtime.jsx)(Button$1, {
10535
+ size: "sm",
10536
+ disabled: state.url === "",
10537
+ onClick: onReload,
10538
+ children: t("preview.url.reload")
10539
+ }),
10540
+ (0, react_jsx_runtime.jsx)(Button$1, {
10541
+ size: "sm",
10542
+ disabled: typed === "",
10543
+ onClick: () => {
10544
+ window.open(typed, "_blank", "noopener,noreferrer");
10545
+ },
10546
+ children: t("preview.newWindow")
10547
+ })
10548
+ ]
10549
+ }),
10550
+ proxied && (0, react_jsx_runtime.jsx)("p", {
10551
+ className: Preview_module_css_default.quiet,
10552
+ children: t("preview.url.proxied")
10553
+ }),
10554
+ publicUrl && (0, react_jsx_runtime.jsx)(Alert, {
10555
+ tone: "default",
10556
+ className: Preview_module_css_default.note,
10557
+ children: t("preview.url.crossOrigin")
10558
+ }),
10559
+ typed === "" && (0, react_jsx_runtime.jsx)("p", {
10560
+ className: Preview_module_css_default.quiet,
10561
+ children: t("preview.url.empty")
10562
+ })
10563
+ ] });
10564
+ }
10565
+
10566
+ //#endregion
10567
+ //#region tsbuild/client/panels/PreviewPanel.js
10568
+ /** How often the panel asks for logs and state while a server is starting. */
10569
+ const FAST_POLL_MS = 400;
10570
+ /** How often it asks once the server is ready and only the log view is watching. */
10571
+ const SLOW_POLL_MS = 1500;
10572
+ /** Retained log lines. */
10573
+ const LOG_LINES = 4e3;
10574
+ /** The viewport sizes the frame can be pinned to, in the order the picker lists them. */
10575
+ const DEVICES = [
10576
+ {
10577
+ id: "desktop",
10578
+ width: 0,
10579
+ height: 0
10580
+ },
10581
+ {
10582
+ id: "tablet",
10583
+ width: 768,
10584
+ height: 1024
10585
+ },
10586
+ {
10587
+ id: "mobile",
10588
+ width: 375,
10589
+ height: 812
10590
+ }
10591
+ ];
10592
+ /** The modes, in tab order. */
10593
+ const MODES = [
10594
+ "server",
10595
+ "file",
10596
+ "url",
10597
+ "scratchpad"
10598
+ ];
10599
+ /**
10600
+ * Status marker for one server state.
10601
+ *
10602
+ * `stopped` has no marker of its own: the dot set carries no neutral member, and a `warning` dot on
10603
+ * a server nobody started would read as something being wrong.
10604
+ * @param state - the server's lifecycle state.
10605
+ * @returns the dot state, or undefined while nothing is running.
10606
+ */
10607
+ function dotState$1(state) {
10608
+ switch (state) {
10609
+ case "ready": return "done";
10610
+ case "starting": return "ongoing";
10611
+ case "failed": return "error";
10612
+ case "exited": return "warning";
10613
+ default: return;
10614
+ }
10615
+ }
10616
+ /**
10617
+ * The four-mode Preview surface, its frame, its logs, and the agent driver.
10618
+ * @param props - the target, the translator, and the dock's face.
10619
+ * @returns the panel body.
10620
+ * @see {@link PanelProps}
10621
+ */
10622
+ function PreviewPanel({ target, t, face }) {
10623
+ const { previewList, previewStart, previewStop, previewLogs, previewFileInfo, previewPoll, previewResult, previewRelease, openPath } = face;
10624
+ const latest = useLatest(t);
10625
+ const directory = target.directory;
10626
+ const [mode, setMode] = (0, react.useState)("server");
10627
+ const [error, setError] = (0, react.useState)(void 0);
10628
+ const [frameKey, setFrameKey] = (0, react.useState)(0);
10629
+ const [viewport, setViewport] = (0, react.useState)({
10630
+ width: 0,
10631
+ height: 0
10632
+ });
10633
+ const [device, setDevice] = (0, react.useState)("desktop");
10634
+ const [stage, setStage] = (0, react.useState)({
10635
+ width: 0,
10636
+ height: 0
10637
+ });
10638
+ const stageRef = (0, react.useRef)(null);
10639
+ const frameRef = (0, react.useRef)(null);
10640
+ const [url, setUrl] = (0, react.useState)("");
10641
+ const [serverAddress, setServerAddress] = (0, react.useState)("");
10642
+ const [filePath, setFilePath] = (0, react.useState)("");
10643
+ const [fileInfo, setFileInfo] = (0, react.useState)(void 0);
10644
+ const [fileBusy, setFileBusy] = (0, react.useState)(false);
10645
+ const [proxyRoute, setProxyRoute] = (0, react.useState)(void 0);
10646
+ const [fileRoute, setFileRoute] = (0, react.useState)(void 0);
10647
+ const [servers, setServers] = (0, react.useState)(void 0);
10648
+ const [launchFile, setLaunchFile] = (0, react.useState)(void 0);
10649
+ const [launchError, setLaunchError] = (0, react.useState)(void 0);
10650
+ const [selected, setSelected] = (0, react.useState)(void 0);
10651
+ const [busy, setBusy] = (0, react.useState)(false);
10652
+ const [generation, setGeneration] = (0, react.useState)(0);
10653
+ const [showLogs, setShowLogs] = (0, react.useState)(false);
10654
+ const [logRevision, setLogRevision] = (0, react.useState)(0);
10655
+ const logs = (0, react.useMemo)(() => new TerminalScreen(LOG_LINES), []);
10656
+ const logOffset = (0, react.useRef)(0);
10657
+ /** The server whose failure already opened the log view; a failed start opens it once, not per poll. */
10658
+ const openedOnFailure = (0, react.useRef)(void 0);
10659
+ const logViewRef = (0, react.useRef)(null);
10660
+ (0, react.useEffect)(() => {
10661
+ let live$1 = true;
10662
+ face.describe().then((view) => {
10663
+ if (!live$1) return;
10664
+ setProxyRoute(view.preview.surface?.available === true ? view.preview.surface.proxyRoute : void 0);
10665
+ setFileRoute(view.preview.surface?.available === true ? view.preview.surface.fileRoute : void 0);
10666
+ }, () => {});
10667
+ return () => {
10668
+ live$1 = false;
10669
+ };
10670
+ }, [face]);
10671
+ (0, react.useEffect)(() => {
10672
+ if (directory === void 0) return;
10673
+ const controller = new AbortController();
10674
+ setError(void 0);
10675
+ previewList(directory, controller.signal).then((result) => {
10676
+ if (controller.signal.aborted) return;
10677
+ if (!result.ok) {
10678
+ setError(result.message);
10679
+ return;
10680
+ }
9180
10681
  setServers(result.servers);
9181
10682
  setLaunchFile(result.launchFile);
9182
10683
  setLaunchError(result.launchFileError);
@@ -9198,7 +10699,7 @@ function PreviewPanel({ target, t, face }) {
9198
10699
  const state = server?.state ?? "stopped";
9199
10700
  const serverUrl = server?.url;
9200
10701
  (0, react.useEffect)(() => {
9201
- setAddress(serverUrl ?? "");
10702
+ setServerAddress(serverUrl ?? "");
9202
10703
  }, [serverUrl, selected]);
9203
10704
  (0, react.useEffect)(() => {
9204
10705
  logs.clear();
@@ -9208,11 +10709,11 @@ function PreviewPanel({ target, t, face }) {
9208
10709
  const watching = serverId !== void 0 && (state === "starting" || showLogs);
9209
10710
  (0, react.useEffect)(() => {
9210
10711
  if (serverId === void 0 || !watching) return;
9211
- let live = true;
10712
+ let live$1 = true;
9212
10713
  let timer = 0;
9213
10714
  const tick = () => {
9214
10715
  previewLogs(serverId, logOffset.current).then((result) => {
9215
- if (!live) return;
10716
+ if (!live$1) return;
9216
10717
  if (result.ok) {
9217
10718
  if (result.text !== "") {
9218
10719
  logs.write(result.text);
@@ -9225,21 +10726,21 @@ function PreviewPanel({ target, t, face }) {
9225
10726
  setShowLogs(true);
9226
10727
  }
9227
10728
  } else if (result.code === "unknown-server") {
9228
- live = false;
10729
+ live$1 = false;
9229
10730
  setGeneration((value) => value + 1);
9230
10731
  return;
9231
10732
  } else setError(result.message);
9232
10733
  const cadence = result.ok && result.server.state === "starting" ? FAST_POLL_MS : SLOW_POLL_MS;
9233
10734
  timer = window.setTimeout(tick, cadence);
9234
10735
  }, (reason) => {
9235
- if (!live) return;
10736
+ if (!live$1) return;
9236
10737
  setError(transportMessage(reason, latest.current));
9237
10738
  timer = window.setTimeout(tick, SLOW_POLL_MS);
9238
10739
  });
9239
10740
  };
9240
10741
  tick();
9241
10742
  return () => {
9242
- live = false;
10743
+ live$1 = false;
9243
10744
  window.clearTimeout(timer);
9244
10745
  };
9245
10746
  }, [
@@ -9250,35 +10751,220 @@ function PreviewPanel({ target, t, face }) {
9250
10751
  latest
9251
10752
  ]);
9252
10753
  (0, react.useEffect)(() => {
9253
- const view = logViewRef.current;
9254
- if (view === null) return;
9255
- if (view.scrollHeight - view.scrollTop - view.clientHeight < 40) view.scrollTop = view.scrollHeight;
9256
- }, [logRevision]);
9257
- const readyMark = state === "ready" ? serverId ?? server?.name : void 0;
9258
- (0, react.useEffect)(() => {
9259
- if (readyMark !== void 0) setFrameKey((value) => value + 1);
9260
- }, [readyMark]);
9261
- (0, react.useEffect)(() => {
9262
- const element = stageRef.current;
9263
- if (element === null || typeof ResizeObserver === "undefined") return;
9264
- const observer = new ResizeObserver(() => {
9265
- setStage({
9266
- width: element.clientWidth,
9267
- height: element.clientHeight
9268
- });
9269
- });
9270
- observer.observe(element);
9271
- setStage({
9272
- width: element.clientWidth,
9273
- height: element.clientHeight
10754
+ const view = logViewRef.current;
10755
+ if (view === null) return;
10756
+ if (view.scrollHeight - view.scrollTop - view.clientHeight < 40) view.scrollTop = view.scrollHeight;
10757
+ }, [logRevision]);
10758
+ const readyMark = state === "ready" ? serverId ?? server?.name : void 0;
10759
+ (0, react.useEffect)(() => {
10760
+ if (readyMark !== void 0) setFrameKey((value) => value + 1);
10761
+ }, [readyMark]);
10762
+ (0, react.useEffect)(() => {
10763
+ const element = stageRef.current;
10764
+ if (element === null || typeof ResizeObserver === "undefined") return;
10765
+ const observer = new ResizeObserver(() => {
10766
+ setStage({
10767
+ width: element.clientWidth,
10768
+ height: element.clientHeight
10769
+ });
10770
+ });
10771
+ observer.observe(element);
10772
+ setStage({
10773
+ width: element.clientWidth,
10774
+ height: element.clientHeight
10775
+ });
10776
+ return () => {
10777
+ observer.disconnect();
10778
+ };
10779
+ }, [showLogs, mode]);
10780
+ const pinned = viewport.width > 0 && viewport.height > 0;
10781
+ const scale = pinned && stage.width > 0 && stage.height > 0 ? Math.min(1, stage.width / viewport.width, stage.height / viewport.height) : 1;
10782
+ const [scratchSrc, setScratchSrc] = (0, react.useState)("");
10783
+ /** Publish one scratchpad document and point the frame at a fresh copy of it. */
10784
+ const publishScratch = (0, react.useCallback)((document_) => {
10785
+ if (fileRoute === void 0) return;
10786
+ fetch(scratchRoute(fileRoute), {
10787
+ method: "POST",
10788
+ headers: { "content-type": "text/html; charset=utf-8" },
10789
+ body: document_
10790
+ }).then((response) => {
10791
+ if (!response.ok) {
10792
+ setError(t("preview.scratch.refused", { status: String(response.status) }));
10793
+ return;
10794
+ }
10795
+ setError(void 0);
10796
+ setScratchSrc(`${scratchRoute(fileRoute)}#${String(Date.now())}`);
10797
+ }, (reason) => {
10798
+ setError(transportMessage(reason, latest.current));
10799
+ });
10800
+ }, [
10801
+ fileRoute,
10802
+ latest,
10803
+ t
10804
+ ]);
10805
+ const scratch = useScratchpad(directory, publishScratch);
10806
+ (0, react.useEffect)(() => {
10807
+ if (modeRef.current !== "scratchpad") return;
10808
+ if (scratchSrc !== "" || fileRoute === void 0) return;
10809
+ publishScratch(scratch.text);
10810
+ }, [
10811
+ fileRoute,
10812
+ scratchSrc,
10813
+ scratch.text,
10814
+ publishScratch
10815
+ ]);
10816
+ const proxied = url.trim() === "" || proxyRoute === void 0 ? {
10817
+ src: url.trim(),
10818
+ sameOrigin: false
10819
+ } : frameUrlFor(proxyRoute, url.trim());
10820
+ const frame = (0, react.useMemo)(() => {
10821
+ if (mode === "server") return {
10822
+ src: serverAddress.trim(),
10823
+ inspectable: false,
10824
+ kind: void 0
10825
+ };
10826
+ if (mode === "url") return {
10827
+ src: proxied.src,
10828
+ inspectable: proxied.sameOrigin,
10829
+ kind: void 0
10830
+ };
10831
+ if (mode === "file") {
10832
+ const framed = fileInfo?.kind === "iframe" && fileInfo.url !== void 0;
10833
+ return {
10834
+ src: framed ? fileInfo.url ?? "" : "",
10835
+ inspectable: framed,
10836
+ kind: fileInfo?.kind
10837
+ };
10838
+ }
10839
+ return {
10840
+ src: scratchSrc,
10841
+ inspectable: scratchSrc !== "",
10842
+ kind: void 0
10843
+ };
10844
+ }, [
10845
+ mode,
10846
+ serverAddress,
10847
+ proxied,
10848
+ fileInfo,
10849
+ scratchSrc
10850
+ ]);
10851
+ useFileWatch(face, directory, fileInfo?.path, (0, react.useCallback)((info) => {
10852
+ setFileInfo(info);
10853
+ }, []), (0, react.useCallback)(() => {
10854
+ setFrameKey((value) => value + 1);
10855
+ }, []));
10856
+ const clientId = (0, react.useMemo)(() => `preview-${Math.random().toString(36).slice(2)}-${String(Date.now())}`, []);
10857
+ const modeRef = (0, react.useRef)(mode);
10858
+ modeRef.current = mode;
10859
+ const live = (0, react.useRef)({
10860
+ src: frame.src,
10861
+ inspectable: frame.inspectable,
10862
+ workspace: directory,
10863
+ filePath,
10864
+ viewport
10865
+ });
10866
+ live.current = {
10867
+ src: frame.src,
10868
+ inspectable: frame.inspectable,
10869
+ workspace: directory,
10870
+ filePath,
10871
+ viewport
10872
+ };
10873
+ /** The file load the driver's `open` performs, without the file mode's own draft state. */
10874
+ const loadInto = (0, react.useCallback)((workspace, path) => {
10875
+ setFileBusy(true);
10876
+ previewFileInfo(workspace, absoluteIn(workspace, path)).then((result) => {
10877
+ setFileBusy(false);
10878
+ if (!result.ok) {
10879
+ setFileInfo(void 0);
10880
+ setError(result.message);
10881
+ return;
10882
+ }
10883
+ setError(void 0);
10884
+ setFileInfo(result);
10885
+ setFrameKey((value) => value + 1);
10886
+ }, (reason) => {
10887
+ setFileBusy(false);
10888
+ setError(transportMessage(reason, latest.current));
10889
+ });
10890
+ }, [previewFileInfo, latest]);
10891
+ const driver = (0, react.useMemo)(() => new PreviewDriver({
10892
+ previewPoll,
10893
+ previewResult,
10894
+ previewRelease
10895
+ }, clientId, target.sessionId, {
10896
+ frame: () => {
10897
+ const element = frameRef.current;
10898
+ if (element === null) return {
10899
+ element: null,
10900
+ document: null,
10901
+ window: null
10902
+ };
10903
+ let document_ = null;
10904
+ let window_ = null;
10905
+ try {
10906
+ document_ = element.contentDocument;
10907
+ window_ = element.contentWindow;
10908
+ } catch {
10909
+ document_ = null;
10910
+ window_ = null;
10911
+ }
10912
+ return {
10913
+ element,
10914
+ document: document_,
10915
+ window: window_
10916
+ };
10917
+ },
10918
+ control: (message) => {
10919
+ if (message.control !== "open") return;
10920
+ const open = message.open;
10921
+ if (open.mode === "file" && open.filePath !== void 0) {
10922
+ setFilePath(open.filePath);
10923
+ if (open.workspacePath !== void 0) loadInto(open.workspacePath, open.filePath);
10924
+ } else if (open.mode === "url" && open.url !== void 0) {
10925
+ setUrl(open.url);
10926
+ setFrameKey((value) => value + 1);
10927
+ }
10928
+ setMode(open.mode);
10929
+ },
10930
+ reload: () => {
10931
+ setFrameKey((value) => value + 1);
10932
+ },
10933
+ resize: (width, height) => {
10934
+ setViewport({
10935
+ width,
10936
+ height
10937
+ });
10938
+ }
10939
+ }), [
10940
+ clientId,
10941
+ target.sessionId,
10942
+ previewPoll,
10943
+ previewResult,
10944
+ previewRelease,
10945
+ loadInto
10946
+ ]);
10947
+ (0, react.useEffect)(() => {
10948
+ driver.start(() => {
10949
+ const current = live.current;
10950
+ return {
10951
+ mounted: current.src !== "",
10952
+ mode: modeRef.current,
10953
+ filePath: modeRef.current === "file" ? current.filePath : void 0,
10954
+ workspacePath: current.workspace,
10955
+ url: current.inspectable ? current.src : void 0,
10956
+ inspectable: current.inspectable,
10957
+ width: current.viewport.width,
10958
+ height: current.viewport.height
10959
+ };
9274
10960
  });
9275
10961
  return () => {
9276
- observer.disconnect();
10962
+ driver.stop();
9277
10963
  };
9278
- }, [showLogs]);
9279
- const preset = DEVICES.find((entry) => entry.id === device) ?? DEVICES[0];
9280
- const framed = preset.width > 0 && preset.height > 0;
9281
- const scale = framed && stage.width > 0 && stage.height > 0 ? Math.min(1, stage.width / preset.width, stage.height / preset.height) : 1;
10964
+ }, [driver]);
10965
+ (0, react.useEffect)(() => () => {
10966
+ previewRelease(clientId);
10967
+ }, [previewRelease, clientId]);
9282
10968
  const start = (0, react.useCallback)(() => {
9283
10969
  if (directory === void 0 || selected === void 0) return;
9284
10970
  setBusy(true);
@@ -9325,9 +11011,29 @@ function PreviewPanel({ target, t, face }) {
9325
11011
  ]);
9326
11012
  const running = state === "starting" || state === "ready";
9327
11013
  const canStart = server?.startable === true && !running && !busy;
9328
- const src = address.trim();
11014
+ /** Show one mode, clearing the error line so a failure from another mode does not follow it. */
11015
+ const showMode = (next) => {
11016
+ setMode(next);
11017
+ setError(void 0);
11018
+ if (next === "scratchpad" && scratchSrc === "" && fileRoute !== void 0) publishScratch(scratch.text);
11019
+ };
11020
+ const markdown = mode === "file" && fileInfo?.kind === "markdown" && fileInfo.url !== void 0 ? fileInfo.url : void 0;
11021
+ const plainText = mode === "file" && fileInfo?.kind === "text" && fileInfo.url !== void 0 ? fileInfo.url : void 0;
11022
+ const drawnHere = markdown !== void 0 || plainText !== void 0;
9329
11023
  return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
9330
- (0, react_jsx_runtime.jsxs)("div", {
11024
+ (0, react_jsx_runtime.jsx)(Tabs, {
11025
+ className: Preview_module_css_default.modes,
11026
+ "aria-label": t("preview.modes"),
11027
+ value: mode,
11028
+ onValueChange: (id) => {
11029
+ showMode(id);
11030
+ },
11031
+ tabs: MODES.map((entry) => ({
11032
+ id: entry,
11033
+ label: t(`preview.mode.${entry}`)
11034
+ }))
11035
+ }),
11036
+ mode === "server" && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsxs)("div", {
9331
11037
  className: Panels_module_css_default.toolbar,
9332
11038
  children: [
9333
11039
  dotState$1(state) !== void 0 ? (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.StateDot, {
@@ -9352,14 +11058,14 @@ function PreviewPanel({ target, t, face }) {
9352
11058
  children: t(`preview.state.${state}`)
9353
11059
  }),
9354
11060
  (0, react_jsx_runtime.jsx)("span", { className: Panels_module_css_default.spacer }),
9355
- running ? (0, react_jsx_runtime.jsx)(Button, {
11061
+ running ? (0, react_jsx_runtime.jsx)(Button$1, {
9356
11062
  size: "icon",
9357
11063
  "aria-label": t("preview.stop"),
9358
11064
  title: t("preview.stop"),
9359
11065
  disabled: busy,
9360
11066
  onClick: stop,
9361
11067
  children: (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconStopFill16, {})
9362
- }) : (0, react_jsx_runtime.jsx)(Button, {
11068
+ }) : (0, react_jsx_runtime.jsx)(Button$1, {
9363
11069
  size: "icon",
9364
11070
  "aria-label": t("preview.start"),
9365
11071
  title: server?.startable === false ? t("preview.notStartable") : t("preview.start"),
@@ -9367,7 +11073,7 @@ function PreviewPanel({ target, t, face }) {
9367
11073
  onClick: start,
9368
11074
  children: busy ? (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconLoadingOutline16, {}) : (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconPlayOutline16, {})
9369
11075
  }),
9370
- (0, react_jsx_runtime.jsx)(Button, {
11076
+ (0, react_jsx_runtime.jsx)(Button$1, {
9371
11077
  size: "sm",
9372
11078
  active: showLogs,
9373
11079
  "aria-label": t("preview.logs"),
@@ -9378,8 +11084,7 @@ function PreviewPanel({ target, t, face }) {
9378
11084
  children: t("preview.logs")
9379
11085
  })
9380
11086
  ]
9381
- }),
9382
- (0, react_jsx_runtime.jsxs)("div", {
11087
+ }), (0, react_jsx_runtime.jsxs)("div", {
9383
11088
  className: Panels_module_css_default.toolbar,
9384
11089
  children: [
9385
11090
  (0, react_jsx_runtime.jsx)(Input, {
@@ -9389,83 +11094,208 @@ function PreviewPanel({ target, t, face }) {
9389
11094
  autoComplete: "off",
9390
11095
  "aria-label": t("preview.address"),
9391
11096
  placeholder: t("preview.address"),
9392
- value: address,
11097
+ value: serverAddress,
9393
11098
  onChange: (event) => {
9394
- setAddress(event.target.value);
11099
+ setServerAddress(event.target.value);
9395
11100
  },
9396
11101
  onKeyDown: (event) => {
9397
11102
  if (event.key === "Enter") setFrameKey((value) => value + 1);
9398
11103
  }
9399
11104
  }),
9400
- (0, react_jsx_runtime.jsx)(Button, {
11105
+ (0, react_jsx_runtime.jsx)(Button$1, {
9401
11106
  size: "icon",
9402
11107
  "aria-label": t("panel.refresh"),
9403
11108
  title: t("panel.refresh"),
9404
- disabled: src === "",
11109
+ disabled: serverAddress.trim() === "",
9405
11110
  onClick: () => {
9406
11111
  setFrameKey((value) => value + 1);
9407
11112
  },
9408
11113
  children: (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline14, {})
9409
11114
  }),
9410
- (0, react_jsx_runtime.jsx)(Button, {
11115
+ (0, react_jsx_runtime.jsx)(Button$1, {
9411
11116
  size: "icon",
9412
11117
  "aria-label": t("preview.newWindow"),
9413
11118
  title: t("preview.newWindow"),
9414
- disabled: src === "",
11119
+ disabled: serverAddress.trim() === "",
9415
11120
  onClick: () => {
9416
- window.open(src, "_blank", "noopener,noreferrer");
11121
+ window.open(serverAddress.trim(), "_blank", "noopener,noreferrer");
9417
11122
  },
9418
11123
  children: (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconRightUpOutline16, {})
9419
11124
  }),
9420
- (0, react_jsx_runtime.jsx)(Select, {
9421
- className: Panels_module_css_default.previewPicker,
9422
- "aria-label": t("preview.device"),
9423
- value: device,
9424
- options: DEVICES.map((entry) => ({
9425
- value: entry.id,
9426
- label: t(`preview.device.${entry.id}`)
9427
- })),
9428
- onValueChange: setDevice
11125
+ (0, react_jsx_runtime.jsx)(Button$1, {
11126
+ size: "sm",
11127
+ disabled: serverUrl === void 0 || proxyRoute === void 0,
11128
+ title: t("preview.inspectHint"),
11129
+ onClick: () => {
11130
+ if (serverUrl === void 0) return;
11131
+ setUrl(serverUrl);
11132
+ showMode("url");
11133
+ },
11134
+ children: t("preview.inspect")
9429
11135
  })
9430
11136
  ]
11137
+ })] }),
11138
+ mode === "file" && (0, react_jsx_runtime.jsx)(PreviewFileMode, {
11139
+ t,
11140
+ face,
11141
+ state: { ...frameState({
11142
+ mode,
11143
+ directory,
11144
+ proxyRoute,
11145
+ filePath,
11146
+ url,
11147
+ viewport,
11148
+ frame
11149
+ }) },
11150
+ setState: (patch) => {
11151
+ if (patch.filePath !== void 0) setFilePath(patch.filePath);
11152
+ if (patch.committed === true) setFrameKey((value) => value + 1);
11153
+ },
11154
+ workspace: directory,
11155
+ info: fileInfo,
11156
+ busy: fileBusy,
11157
+ onInfo: setFileInfo,
11158
+ onError: setError,
11159
+ onReload: () => {
11160
+ setFrameKey((value) => value + 1);
11161
+ }
11162
+ }),
11163
+ mode === "url" && (0, react_jsx_runtime.jsx)(PreviewUrlMode, {
11164
+ t,
11165
+ state: frameState({
11166
+ mode,
11167
+ directory,
11168
+ proxyRoute,
11169
+ filePath,
11170
+ url,
11171
+ viewport,
11172
+ frame
11173
+ }),
11174
+ setState: (patch) => {
11175
+ if (patch.url !== void 0) setUrl(patch.url);
11176
+ if (patch.committed === true) setFrameKey((value) => value + 1);
11177
+ },
11178
+ onReload: () => {
11179
+ setFrameKey((value) => value + 1);
11180
+ }
11181
+ }),
11182
+ mode === "scratchpad" && (0, react_jsx_runtime.jsx)(PreviewScratchpadMode, {
11183
+ t,
11184
+ state: frameState({
11185
+ mode,
11186
+ directory,
11187
+ proxyRoute,
11188
+ filePath,
11189
+ url,
11190
+ viewport,
11191
+ frame
11192
+ }),
11193
+ setState: () => {},
11194
+ scratch,
11195
+ onReload: () => {
11196
+ publishScratch(scratch.text);
11197
+ }
9431
11198
  }),
9432
11199
  error !== void 0 && (0, react_jsx_runtime.jsx)(Alert, {
9433
11200
  tone: "destructive",
9434
11201
  className: Panels_module_css_default.panelAlert,
9435
11202
  children: error
9436
11203
  }),
9437
- launchError !== void 0 && (0, react_jsx_runtime.jsx)("p", {
11204
+ mode === "server" && launchError !== void 0 && (0, react_jsx_runtime.jsx)("p", {
9438
11205
  className: Panels_module_css_default.quiet,
9439
11206
  children: launchError
9440
11207
  }),
9441
- server?.detail !== void 0 && state !== "ready" && (0, react_jsx_runtime.jsx)("p", {
11208
+ mode === "server" && server?.detail !== void 0 && state !== "ready" && (0, react_jsx_runtime.jsx)("p", {
9442
11209
  className: Panels_module_css_default.quiet,
9443
11210
  children: server.detail
9444
11211
  }),
9445
- servers?.length === 0 && (0, react_jsx_runtime.jsx)("p", {
11212
+ mode === "server" && servers?.length === 0 && (0, react_jsx_runtime.jsx)("p", {
9446
11213
  className: Panels_module_css_default.quiet,
9447
11214
  children: launchFile === void 0 ? t("preview.empty") : t("preview.emptyFile", { file: launchFile })
9448
11215
  }),
9449
- (0, react_jsx_runtime.jsx)("div", {
9450
- ref: stageRef,
9451
- className: cx(Panels_module_css_default.previewStage, showLogs && Panels_module_css_default.previewStageShort),
9452
- children: src === "" ? (0, react_jsx_runtime.jsx)("p", {
9453
- className: Panels_module_css_default.quiet,
9454
- children: t("preview.noUrl")
9455
- }) : (0, react_jsx_runtime.jsx)("iframe", {
9456
- className: Panels_module_css_default.previewFrame,
9457
- src,
9458
- title: t("preview.frame", { name: server?.name ?? "" }),
9459
- style: framed ? {
9460
- width: `${String(preset.width)}px`,
9461
- height: `${String(preset.height)}px`,
9462
- transform: `scale(${String(scale)})`
9463
- } : void 0,
9464
- sandbox: "allow-scripts allow-same-origin allow-forms allow-popups allow-modals",
9465
- referrerPolicy: "no-referrer"
9466
- }, frameKey)
11216
+ mode === "file" && fileInfo !== void 0 && (!fileInfo.withinLimit || fileInfo.kind === "other") && (0, react_jsx_runtime.jsxs)("div", {
11217
+ className: cx(Preview_module_css_default.empty, Panels_module_css_default.previewStageShort),
11218
+ children: [
11219
+ (0, react_jsx_runtime.jsx)("p", { children: fileInfo.withinLimit ? t("preview.file.notPreviewable") : t("preview.file.overLimit") }),
11220
+ (0, react_jsx_runtime.jsx)("p", { children: t("preview.file.facts", {
11221
+ name: fileInfo.name,
11222
+ kind: t(`preview.kind.${fileInfo.kind}`),
11223
+ bytes: formatBytes(fileInfo.bytes)
11224
+ }) }),
11225
+ (0, react_jsx_runtime.jsx)("div", {
11226
+ className: Preview_module_css_default.emptyActions,
11227
+ children: (0, react_jsx_runtime.jsx)(Button$1, {
11228
+ size: "sm",
11229
+ onClick: () => {
11230
+ openPath(fileInfo.path);
11231
+ },
11232
+ children: t("files.open")
11233
+ })
11234
+ })
11235
+ ]
9467
11236
  }),
9468
- showLogs && (0, react_jsx_runtime.jsxs)("div", {
11237
+ mode !== "file" || fileInfo === void 0 || fileInfo.withinLimit && fileInfo.kind !== "other" ? (0, react_jsx_runtime.jsxs)("div", {
11238
+ ref: stageRef,
11239
+ className: cx(Panels_module_css_default.previewStage, Preview_module_css_default.stageHost, showLogs && mode === "server" && Panels_module_css_default.previewStageShort),
11240
+ children: [
11241
+ mode === "file" && fileInfo?.kind === "image" && fileInfo.url !== void 0 && (0, react_jsx_runtime.jsx)("img", {
11242
+ className: Preview_module_css_default.media,
11243
+ src: fileInfo.url,
11244
+ alt: fileInfo.name
11245
+ }),
11246
+ mode === "file" && fileInfo?.kind === "pdf" && fileInfo.url !== void 0 && (0, react_jsx_runtime.jsx)("iframe", {
11247
+ className: Preview_module_css_default.pdfPane,
11248
+ src: fileInfo.url,
11249
+ title: t("preview.frame", { name: fileInfo.name })
11250
+ }),
11251
+ mode === "file" && fileInfo?.kind === "media" && fileInfo.url !== void 0 && (isAudio(fileInfo.contentType) ? (0, react_jsx_runtime.jsx)("audio", {
11252
+ className: Preview_module_css_default.media,
11253
+ src: fileInfo.url,
11254
+ controls: true
11255
+ }) : (0, react_jsx_runtime.jsx)("video", {
11256
+ className: Preview_module_css_default.media,
11257
+ src: fileInfo.url,
11258
+ controls: true
11259
+ })),
11260
+ markdown !== void 0 && (0, react_jsx_runtime.jsx)("div", {
11261
+ className: Preview_module_css_default.markdownPane,
11262
+ children: (0, react_jsx_runtime.jsx)(RemoteText, {
11263
+ url: markdown,
11264
+ render: (text) => (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.MarkdownText, { text }),
11265
+ t
11266
+ })
11267
+ }),
11268
+ plainText !== void 0 && (0, react_jsx_runtime.jsx)("div", {
11269
+ className: Preview_module_css_default.markdownPane,
11270
+ children: (0, react_jsx_runtime.jsx)(RemoteText, {
11271
+ url: plainText,
11272
+ render: (text) => (0, react_jsx_runtime.jsx)("pre", {
11273
+ className: Panels_module_css_default.previewText,
11274
+ children: text
11275
+ }),
11276
+ t
11277
+ })
11278
+ }),
11279
+ frame.src !== "" && !(mode === "file" && (fileInfo?.kind === "image" || fileInfo?.kind === "media" || fileInfo?.kind === "pdf")) && (0, react_jsx_runtime.jsx)("iframe", {
11280
+ ref: frameRef,
11281
+ className: cx(Panels_module_css_default.previewFrame, drawnHere && Preview_module_css_default.frameUnder),
11282
+ src: frame.src,
11283
+ title: t("preview.frame", { name: frameName(mode, fileInfo, server?.name ?? "") }),
11284
+ style: pinned ? {
11285
+ width: `${String(viewport.width)}px`,
11286
+ height: `${String(viewport.height)}px`,
11287
+ transform: `scale(${String(scale)})`
11288
+ } : void 0,
11289
+ sandbox: "allow-scripts allow-same-origin allow-forms allow-popups allow-modals",
11290
+ referrerPolicy: "no-referrer"
11291
+ }, frameKey),
11292
+ frame.src === "" && markdown === void 0 && plainText === void 0 && !(mode === "file" && fileInfo !== void 0) && (0, react_jsx_runtime.jsx)("p", {
11293
+ className: Panels_module_css_default.quiet,
11294
+ children: mode === "server" ? t("preview.noUrl") : t("preview.frame.empty")
11295
+ })
11296
+ ]
11297
+ }) : null,
11298
+ mode === "server" && showLogs && (0, react_jsx_runtime.jsxs)("div", {
9469
11299
  ref: logViewRef,
9470
11300
  className: Panels_module_css_default.previewLogs,
9471
11301
  children: [(0, react_jsx_runtime.jsx)("pre", {
@@ -9475,9 +11305,117 @@ function PreviewPanel({ target, t, face }) {
9475
11305
  className: Panels_module_css_default.quiet,
9476
11306
  children: t("preview.logs.empty")
9477
11307
  })]
11308
+ }),
11309
+ (0, react_jsx_runtime.jsxs)("div", {
11310
+ className: cx(Panels_module_css_default.toolbar, Preview_module_css_default.viewportBar),
11311
+ children: [
11312
+ (0, react_jsx_runtime.jsx)("span", {
11313
+ className: Panels_module_css_default.quietInline,
11314
+ children: pinned ? t("preview.viewport.custom", {
11315
+ width: String(viewport.width),
11316
+ height: String(viewport.height)
11317
+ }) : t("preview.viewport.fit")
11318
+ }),
11319
+ (0, react_jsx_runtime.jsx)("span", { className: Panels_module_css_default.spacer }),
11320
+ (0, react_jsx_runtime.jsx)(Select, {
11321
+ className: Panels_module_css_default.previewPicker,
11322
+ "aria-label": t("preview.device"),
11323
+ value: device,
11324
+ options: DEVICES.map((entry) => ({
11325
+ value: entry.id,
11326
+ label: t(`preview.device.${entry.id}`)
11327
+ })),
11328
+ onValueChange: (next) => {
11329
+ const chosen = next;
11330
+ setDevice(chosen);
11331
+ const preset = DEVICES.find((entry) => entry.id === chosen);
11332
+ setViewport({
11333
+ width: preset?.width ?? 0,
11334
+ height: preset?.height ?? 0
11335
+ });
11336
+ }
11337
+ })
11338
+ ]
9478
11339
  })
9479
11340
  ] });
9480
11341
  }
11342
+ /**
11343
+ * Assemble the shared mode state one mode's controls read.
11344
+ * @param input - the panel's own state plus the computed frame.
11345
+ * @returns the mode state.
11346
+ */
11347
+ function frameState(input$1) {
11348
+ return {
11349
+ src: input$1.frame.src,
11350
+ url: input$1.mode === "file" ? input$1.filePath : input$1.url,
11351
+ workspace: input$1.directory,
11352
+ proxyRoute: input$1.proxyRoute,
11353
+ inspectable: input$1.frame.inspectable,
11354
+ filePath: input$1.filePath,
11355
+ viewport: input$1.viewport
11356
+ };
11357
+ }
11358
+ /**
11359
+ * Whether a media MIME type is audio rather than video.
11360
+ * @param contentType - the type.
11361
+ * @returns true for audio.
11362
+ */
11363
+ function isAudio(contentType) {
11364
+ return contentType.startsWith("audio/");
11365
+ }
11366
+ /**
11367
+ * The name a frame's accessible title reports.
11368
+ *
11369
+ * Read by a screen reader and by nothing else, so it is not translated: the panel's visible labels
11370
+ * carry the translated names, and a frame title is an implementation detail of the element.
11371
+ * @param mode - the current mode.
11372
+ * @param info - the file's description, when the mode is `file`.
11373
+ * @param server - the selected server's name, when the mode is `server`.
11374
+ * @returns the name.
11375
+ */
11376
+ function frameName(mode, info, server) {
11377
+ if (mode === "file") return info?.name ?? "file";
11378
+ if (mode === "server") return server;
11379
+ if (mode === "scratchpad") return "scratchpad";
11380
+ return "URL";
11381
+ }
11382
+ /**
11383
+ * Fetch a text document from this Host's own route and render it.
11384
+ *
11385
+ * The bytes come over the same-origin route rather than through a Remote endpoint because that route
11386
+ * is already bounded, typed, and uncached for exactly this document — and because a Markdown file is
11387
+ * rendered from text, so the panel must hold it rather than frame it.
11388
+ * @param props.url - the same-origin file URL.
11389
+ * @param props.render - how to render the loaded text.
11390
+ * @param props.t - the translator, for the failure line.
11391
+ * @returns the rendered document, or the reason it could not be read.
11392
+ */
11393
+ function RemoteText({ url, render, t }) {
11394
+ const [text, setText] = (0, react.useState)(void 0);
11395
+ const [error, setError] = (0, react.useState)(void 0);
11396
+ (0, react.useEffect)(() => {
11397
+ let live = true;
11398
+ setText(void 0);
11399
+ setError(void 0);
11400
+ fetch(url).then((response) => response.ok ? response.text() : Promise.reject(/* @__PURE__ */ new Error(`HTTP ${String(response.status)}`)), (reason) => Promise.reject(reason instanceof Error ? reason : new Error(String(reason)))).then((body) => {
11401
+ if (live) setText(body);
11402
+ }, (reason) => {
11403
+ if (live) setError(t("preview.file.readFailed", { message: reason instanceof Error ? reason.message : String(reason) }));
11404
+ });
11405
+ return () => {
11406
+ live = false;
11407
+ };
11408
+ }, [url, t]);
11409
+ if (error !== void 0) return (0, react_jsx_runtime.jsx)(Alert, {
11410
+ tone: "destructive",
11411
+ children: error
11412
+ });
11413
+ if (text === void 0) return (0, react_jsx_runtime.jsx)("p", {
11414
+ className: Panels_module_css_default.quiet,
11415
+ children: t("panel.loading")
11416
+ });
11417
+ return render(text);
11418
+ }
9481
11419
 
9482
11420
  //#endregion
9483
11421
  //#region tsbuild/client/panels/TasksPanel.js
@@ -9749,7 +11687,7 @@ function TasksPanel({ target, t, face, useSessions, settings }) {
9749
11687
  className: Panels_module_css_default.taskDuration,
9750
11688
  children: formatDuration(elapsed, t)
9751
11689
  }),
9752
- canStop && live && (0, react_jsx_runtime.jsx)(Button, {
11690
+ canStop && live && (0, react_jsx_runtime.jsx)(Button$1, {
9753
11691
  size: "icon",
9754
11692
  "aria-label": t("tasks.stop"),
9755
11693
  title: t("tasks.stop"),
@@ -23095,7 +25033,7 @@ function TerminalView({ tab, groupKey, directory, active, t, face }) {
23095
25033
  children: exit
23096
25034
  }),
23097
25035
  (0, react_jsx_runtime.jsx)("span", { className: Panels_module_css_default.spacer }),
23098
- (0, react_jsx_runtime.jsx)(Button, {
25036
+ (0, react_jsx_runtime.jsx)(Button$1, {
23099
25037
  size: "icon",
23100
25038
  "aria-label": t("terminal.interrupt"),
23101
25039
  title: t("terminal.interrupt"),
@@ -23105,7 +25043,7 @@ function TerminalView({ tab, groupKey, directory, active, t, face }) {
23105
25043
  },
23106
25044
  children: (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconStopFill16, {})
23107
25045
  }),
23108
- (0, react_jsx_runtime.jsx)(Button, {
25046
+ (0, react_jsx_runtime.jsx)(Button$1, {
23109
25047
  size: "icon",
23110
25048
  "aria-label": t("terminal.clear"),
23111
25049
  title: t("terminal.clear"),
@@ -23114,7 +25052,7 @@ function TerminalView({ tab, groupKey, directory, active, t, face }) {
23114
25052
  },
23115
25053
  children: (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, {})
23116
25054
  }),
23117
- (0, react_jsx_runtime.jsx)(Button, {
25055
+ (0, react_jsx_runtime.jsx)(Button$1, {
23118
25056
  size: "icon",
23119
25057
  "aria-label": t("terminal.restart"),
23120
25058
  title: t("terminal.restart"),
@@ -23194,7 +25132,7 @@ function TerminalPanel({ target, t, face, useSidebar, settings }) {
23194
25132
  onClose: (id) => {
23195
25133
  closeTerminal(key, id);
23196
25134
  },
23197
- children: (0, react_jsx_runtime.jsx)(Button, {
25135
+ children: (0, react_jsx_runtime.jsx)(Button$1, {
23198
25136
  size: "icon",
23199
25137
  "aria-label": t("terminal.new"),
23200
25138
  title: tabs.length >= limit ? t("terminal.limit", { count: limit }) : t("terminal.new"),
@@ -23229,16 +25167,16 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
23229
25167
  document.head.appendChild(tag);
23230
25168
  }
23231
25169
  var PanelHost_module_css_default = {
25170
+ "resize": "KfDt9q_resize",
25171
+ "noticeSlot": "KfDt9q_noticeSlot",
25172
+ "head": "KfDt9q_head",
23232
25173
  "dockFloating": "KfDt9q_dockFloating",
23233
- "dockDragging": "KfDt9q_dockDragging",
25174
+ "body": "KfDt9q_body",
23234
25175
  "title": "KfDt9q_title",
23235
- "head": "KfDt9q_head",
25176
+ "dockDragging": "KfDt9q_dockDragging",
23236
25177
  "dock": "KfDt9q_dock",
23237
- "resize": "KfDt9q_resize",
23238
25178
  "headText": "KfDt9q_headText",
23239
- "noticeSlot": "KfDt9q_noticeSlot",
23240
- "subtitle": "KfDt9q_subtitle",
23241
- "body": "KfDt9q_body"
25179
+ "subtitle": "KfDt9q_subtitle"
23242
25180
  };
23243
25181
 
23244
25182
  //#endregion
@@ -23476,7 +25414,7 @@ function PanelHost(props) {
23476
25414
  value: target.directory,
23477
25415
  className: PanelHost_module_css_default.subtitle
23478
25416
  })]
23479
- }), (0, react_jsx_runtime.jsx)(Button, {
25417
+ }), (0, react_jsx_runtime.jsx)(Button$1, {
23480
25418
  size: "icon",
23481
25419
  "aria-label": t("panel.close"),
23482
25420
  onClick: close,
@@ -23523,7 +25461,7 @@ function PanelHost(props) {
23523
25461
  className: PanelHost_module_css_default.noticeSlot,
23524
25462
  children: (0, react_jsx_runtime.jsx)(Alert, {
23525
25463
  tone: notice.tone === "error" ? "destructive" : "default",
23526
- action: (0, react_jsx_runtime.jsx)(Button, {
25464
+ action: (0, react_jsx_runtime.jsx)(Button$1, {
23527
25465
  size: "icon",
23528
25466
  "aria-label": t("notice.dismiss"),
23529
25467
  onClick: () => {
@@ -23562,26 +25500,26 @@ if (typeof document !== "undefined" && document.querySelector("style[data-plugin
23562
25500
  document.head.appendChild(tag);
23563
25501
  }
23564
25502
  var SettingsCard_module_css_default = {
23565
- "hint": "TDpdwq_hint",
23566
- "description": "TDpdwq_description",
23567
25503
  "headText": "TDpdwq_headText",
23568
- "target": "TDpdwq_target",
23569
- "header": "TDpdwq_header",
23570
- "name": "TDpdwq_name",
23571
- "chevronOpen": "TDpdwq_chevronOpen",
25504
+ "head": "TDpdwq_head",
23572
25505
  "groupHead": "TDpdwq_groupHead",
25506
+ "select": "TDpdwq_select",
23573
25507
  "label": "TDpdwq_label",
25508
+ "header": "TDpdwq_header",
23574
25509
  "targets": "TDpdwq_targets",
23575
- "targetLabel": "TDpdwq_targetLabel",
23576
- "field": "TDpdwq_field",
23577
- "shellInput": "TDpdwq_shellInput",
23578
- "select": "TDpdwq_select",
25510
+ "card": "TDpdwq_card",
23579
25511
  "chevron": "TDpdwq_chevron",
23580
25512
  "body": "TDpdwq_body",
25513
+ "targetLabel": "TDpdwq_targetLabel",
25514
+ "description": "TDpdwq_description",
23581
25515
  "groupTitle": "TDpdwq_groupTitle",
23582
- "head": "TDpdwq_head",
23583
- "card": "TDpdwq_card",
23584
- "cardOpen": "TDpdwq_cardOpen"
25516
+ "chevronOpen": "TDpdwq_chevronOpen",
25517
+ "hint": "TDpdwq_hint",
25518
+ "shellInput": "TDpdwq_shellInput",
25519
+ "field": "TDpdwq_field",
25520
+ "cardOpen": "TDpdwq_cardOpen",
25521
+ "target": "TDpdwq_target",
25522
+ "name": "TDpdwq_name"
23585
25523
  };
23586
25524
 
23587
25525
  //#endregion
@@ -23770,7 +25708,7 @@ function SettingsCard(props) {
23770
25708
  children: t("settings.group.limits")
23771
25709
  })
23772
25710
  }),
23773
- number$2("panelWidth", t("settings.panelWidth"), t("settings.panelWidth.hint"), value.panelWidth, 280, 1400),
25711
+ number$2("panelWidth", t("settings.panelWidth"), t("settings.panelWidth.hint"), value.panelWidth, 280, 960),
23774
25712
  number$2("gitMaxFiles", t("settings.gitMaxFiles"), t("settings.gitMaxFiles.hint"), value.gitMaxFiles, 1, 1e4),
23775
25713
  number$2("gitTimeoutMs", t("settings.gitTimeoutMs"), t("settings.gitTimeoutMs.hint"), value.gitTimeoutMs, 1e3, 6e5),
23776
25714
  number$2("gitCommitTimeoutMs", t("settings.gitCommitTimeoutMs"), t("settings.gitCommitTimeoutMs.hint"), value.gitCommitTimeoutMs, 1e3, 18e5),
@@ -23888,6 +25826,8 @@ var ActionMenu_module_css_default = {
23888
25826
  const OPEN_IN_PREFIX = "open-in:";
23889
25827
  /** The Open in entry for a second browser window; not a Host target, so it has no configured id. */
23890
25828
  const NEW_WINDOW_ID = `${OPEN_IN_PREFIX}new-window`;
25829
+ /** The menu id of Download session log; not a panel, so it has no {@link PanelKind}. */
25830
+ const DOWNLOAD_LOG_ID = "download-log";
23891
25831
  /**
23892
25832
  * The trigger plus its menu.
23893
25833
  * @param props - the target, settings, capability view, translator, and callbacks.
@@ -23895,7 +25835,7 @@ const NEW_WINDOW_ID = `${OPEN_IN_PREFIX}new-window`;
23895
25835
  * @see {@link ActionMenuProps}
23896
25836
  */
23897
25837
  function ActionMenu(props) {
23898
- const { target, settings, view, t, actions, refresh, openPanel } = props;
25838
+ const { target, settings, view, t, actions, refresh, openPanel, logDownload, logsOnly } = props;
23899
25839
  const [open, setOpen] = (0, react.useState)(false);
23900
25840
  const triggerRef = (0, react.useRef)(null);
23901
25841
  (0, react.useEffect)(() => {
@@ -23911,6 +25851,7 @@ function ActionMenu(props) {
23911
25851
  had.current = false;
23912
25852
  }, [open, target]);
23913
25853
  if (settings === void 0) return null;
25854
+ const shown = (flag) => flag && !logsOnly;
23914
25855
  const directory = target?.directory;
23915
25856
  const unavailable = (state) => {
23916
25857
  if (target === void 0) return t("menu.noSession");
@@ -23931,11 +25872,11 @@ function ActionMenu(props) {
23931
25872
  checked: openPanel === id
23932
25873
  });
23933
25874
  };
23934
- if (settings.showChanges) panelRow("changes", "menu.changes", (0, react_jsx_runtime.jsx)(ChangesGlyph, { size: 16 }), view?.git);
23935
- if (settings.showTerminal) panelRow("terminal", "menu.terminal", (0, react_jsx_runtime.jsx)(TerminalGlyph, { size: 16 }), view?.terminal);
23936
- if (settings.showFiles) panelRow("files", "menu.files", (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, {}), view?.files);
23937
- if (settings.showPreview) panelRow("preview", "menu.preview", (0, react_jsx_runtime.jsx)(PreviewGlyph, { size: 16 }), view?.preview);
23938
- if (settings.showTasks) {
25875
+ if (shown(settings.showChanges)) panelRow("changes", "menu.changes", (0, react_jsx_runtime.jsx)(ChangesGlyph, { size: 16 }), view?.git);
25876
+ if (shown(settings.showTerminal)) panelRow("terminal", "menu.terminal", (0, react_jsx_runtime.jsx)(TerminalGlyph, { size: 16 }), view?.terminal);
25877
+ if (shown(settings.showFiles)) panelRow("files", "menu.files", (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, {}), view?.files);
25878
+ if (shown(settings.showPreview)) panelRow("preview", "menu.preview", (0, react_jsx_runtime.jsx)(PreviewGlyph, { size: 16 }), view?.preview);
25879
+ if (shown(settings.showTasks)) {
23939
25880
  const note = target === void 0 ? t("menu.noSession") : view?.tasks.available === false ? view.tasks.reason ?? t("settings.unavailable") : void 0;
23940
25881
  items.push({
23941
25882
  kind: "item",
@@ -23947,7 +25888,7 @@ function ActionMenu(props) {
23947
25888
  checked: openPanel === "tasks"
23948
25889
  });
23949
25890
  }
23950
- if (settings.showOpenIn) {
25891
+ if (shown(settings.showOpenIn)) {
23951
25892
  const submenu = [{
23952
25893
  kind: "item",
23953
25894
  id: NEW_WINDOW_ID,
@@ -23973,7 +25914,18 @@ function ActionMenu(props) {
23973
25914
  });
23974
25915
  }
23975
25916
  const sessionEntries = [];
23976
- if (settings.showArchive) sessionEntries.push({
25917
+ if (logDownload.active) {
25918
+ const note = target === void 0 ? t("menu.noSession") : logDownload.busy ? t("menu.downloadLog.busy") : void 0;
25919
+ sessionEntries.push({
25920
+ kind: "item",
25921
+ id: DOWNLOAD_LOG_ID,
25922
+ label: t("menu.downloadLog"),
25923
+ note,
25924
+ icon: (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconDownloadOutline16, {}),
25925
+ disabled: note !== void 0
25926
+ });
25927
+ }
25928
+ if (shown(settings.showArchive)) sessionEntries.push({
23977
25929
  kind: "item",
23978
25930
  id: "archive",
23979
25931
  label: t("menu.archive"),
@@ -23981,7 +25933,7 @@ function ActionMenu(props) {
23981
25933
  icon: (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.IconArchiveOutline20, { size: 16 }),
23982
25934
  disabled: target === void 0
23983
25935
  });
23984
- if (settings.showDelete) sessionEntries.push({
25936
+ if (shown(settings.showDelete)) sessionEntries.push({
23985
25937
  kind: "item",
23986
25938
  id: "delete",
23987
25939
  label: t("menu.delete"),
@@ -24009,6 +25961,10 @@ function ActionMenu(props) {
24009
25961
  actions.openIn(id.slice(8), directory);
24010
25962
  return;
24011
25963
  }
25964
+ if (id === DOWNLOAD_LOG_ID) {
25965
+ actions.downloadLog(target.sessionId);
25966
+ return;
25967
+ }
24012
25968
  if (id === "archive") {
24013
25969
  actions.archive(target);
24014
25970
  return;
@@ -24020,7 +25976,7 @@ function ActionMenu(props) {
24020
25976
  if (id === "changes" || id === "terminal" || id === "files" || id === "tasks" || id === "preview") actions.openPanel(id, target);
24021
25977
  };
24022
25978
  const label = t("menu.trigger");
24023
- return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(Button, {
25979
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(Button$1, {
24024
25980
  ref: triggerRef,
24025
25981
  size: "icon",
24026
25982
  className: cx(ActionMenu_module_css_default.trigger, open && ActionMenu_module_css_default.triggerOpen),
@@ -24046,6 +26002,189 @@ function ActionMenu(props) {
24046
26002
  })] });
24047
26003
  }
24048
26004
 
26005
+ //#endregion
26006
+ //#region tsbuild/client/log-download.js
26007
+ /**
26008
+ * Download session log, absorbed into this plugin's menu.
26009
+ *
26010
+ * The harness ships `@deepseek-ai/dsh-session-log-export`, whose browser half does two things: it
26011
+ * provides a `sessionLogDownload` controller on the client context (`lib/client.js:263`: one
26012
+ * in-flight export per session, and a snapshot store describing it), and it registers a SECOND "⋯"
26013
+ * button into the same
26014
+ * `conversation.session.header.utilities` row this plugin's menu sits in, whose only entry is
26015
+ * "Download session log" and which also renders the progress dialog. Two identical-looking triggers
26016
+ * side by side, one of them holding a single verb, is what this module removes.
26017
+ *
26018
+ * How, and why this way (installed harness 0.1.5-rc.2):
26019
+ *
26020
+ * - The verb is REUSED, not rebuilt. The menu calls the package's own controller, read through the
26021
+ * context service it provides, so the export request, the per-session de-duplication and the
26022
+ * browser save stay the harness's; nothing here knows the export endpoint.
26023
+ * - The button is SHADOWED, not patched out. `…/dsh-session-log-export/lib/client.js:274-276` registers
26024
+ * into a `list` slot with `id: 'session-log-download'` at the default priority 0, and a list slot's
26025
+ * cell is its `id`: entries sharing one coexist at distinct priorities and the lowest live one
26026
+ * renders (`SlotCore.register` / `entriesOfSlot` in `@deepseek-ai/dsh-client-ui-slots`). This
26027
+ * plugin registers that same id at priority -1, so its entry takes the cell without the other
26028
+ * package noticing, and uninstalling this plugin hands the button straight back. The rejected
26029
+ * alternative was a profile `cordis.patch.yml` row disabling the package: that would also remove
26030
+ * the controller the menu calls and the `/export` command's dialog, and it asks every user to edit
26031
+ * their profile.
26032
+ * - The dialog is RE-RENDERED here. The harness's entry renders its button and its dialog as one
26033
+ * component, and the module exports neither, so shadowing the cell takes the dialog with it. The
26034
+ * shadowing entry therefore renders the same `Modal` from the same primitives, bound to the same
26035
+ * store — which keeps `/export`, whose success also opens that dialog, working exactly as before.
26036
+ *
26037
+ * Everything degrades toward the harness's own behaviour rather than toward a missing verb: without
26038
+ * the package, or with a controller whose shape no longer matches, nothing is shadowed and the menu
26039
+ * has no Download entry; and the menu entry and the dialog appear only while the harness's button is
26040
+ * actually being shadowed, so a future harness that renames or removes its seat can never produce
26041
+ * two dialogs, or a verb in two places.
26042
+ * @module @achasoft/dsh-advanced-sidebar/client/log-download
26043
+ */
26044
+ /** The context service the harness package provides (`ctx.provide('sessionLogDownload', …)`). */
26045
+ const LOG_DOWNLOAD_SERVICE = "sessionLogDownload";
26046
+ /** The header slot both the harness's button and this plugin's menu occupy. */
26047
+ const LOG_DOWNLOAD_SLOT = "conversation.session.header.utilities";
26048
+ /** The list-slot cell the harness's download button occupies, and this plugin's entry shadows. */
26049
+ const LOG_DOWNLOAD_SEAT_ID = "session-log-download";
26050
+ /**
26051
+ * The shadowing rank. The harness registers at the default 0; one below is enough to render first,
26052
+ * and staying next to the default leaves room for a profile to out-rank this plugin in turn.
26053
+ */
26054
+ const LOG_DOWNLOAD_SHADOW_PRIORITY = -1;
26055
+ /**
26056
+ * Accept a context service only when it still has the shape this plugin calls.
26057
+ *
26058
+ * The service is another package's, versioned with the harness, so its shape is checked rather than
26059
+ * trusted: an incompatible controller makes this plugin stand aside — no shadow, no menu entry —
26060
+ * which leaves the harness's own button in place instead of a menu entry that throws.
26061
+ * @param value - whatever `ctx.get('sessionLogDownload')` returned.
26062
+ * @returns the service, or undefined when absent or incompatible.
26063
+ */
26064
+ function asLogDownloadService(value) {
26065
+ if (typeof value !== "object" || value === null) return void 0;
26066
+ const candidate = value;
26067
+ const store = candidate.store;
26068
+ if (typeof candidate.download !== "function" || typeof candidate.dismiss !== "function") return void 0;
26069
+ if (typeof store !== "object" || store === null) return void 0;
26070
+ if (typeof store.getSnapshot !== "function" || typeof store.subscribe !== "function") return void 0;
26071
+ return value;
26072
+ }
26073
+ /**
26074
+ * Whether the header row holds an entry this plugin's shadow is actually hiding.
26075
+ *
26076
+ * Checked against the live registry rather than assumed, because the id is the harness's and can
26077
+ * change in an upgrade. Without an occupant to hide, the menu entry would duplicate a download
26078
+ * affordance the harness moved elsewhere, and the dialog would open twice beside the harness's own.
26079
+ * @param entries - the slot's raw entries, every priority included.
26080
+ * @returns true when some entry of the download cell ranks after (numerically above) this plugin's
26081
+ * shadow, and is therefore the one being hidden.
26082
+ */
26083
+ function shadowsHarnessSeat(entries) {
26084
+ return entries.some((entry) => entry.options.id === LOG_DOWNLOAD_SEAT_ID && (entry.options.priority ?? 0) > LOG_DOWNLOAD_SHADOW_PRIORITY);
26085
+ }
26086
+ /** The detached view, shared so an unchanged snapshot keeps one identity. */
26087
+ const DETACHED = {
26088
+ active: false,
26089
+ bySession: {}
26090
+ };
26091
+ /**
26092
+ * Whether one session's export is in flight.
26093
+ * @param view - the bridge snapshot.
26094
+ * @param sessionId - the session to ask about.
26095
+ * @returns true while that session's export has not settled.
26096
+ */
26097
+ function isDownloading(view, sessionId) {
26098
+ return view.bySession[sessionId]?.status === "downloading";
26099
+ }
26100
+ /**
26101
+ * Bridges the harness controller, which may arrive late, leave, or never exist, into one observable
26102
+ * the menu can bind unconditionally.
26103
+ *
26104
+ * A `use<Name>` hook cannot be bound conditionally, and the menu is registered before the harness
26105
+ * package has necessarily loaded, so the menu binds to this instead of to the controller's store:
26106
+ * detached it reports inactive, attached it mirrors the controller's state.
26107
+ */
26108
+ var LogDownloadBridge = class {
26109
+ state = DETACHED;
26110
+ listeners = /* @__PURE__ */ new Set();
26111
+ service;
26112
+ shadowing = false;
26113
+ /**
26114
+ * The current snapshot; stable between changes, as `useSyncExternalStore` requires.
26115
+ * @returns the view.
26116
+ */
26117
+ getSnapshot() {
26118
+ return this.state;
26119
+ }
26120
+ /**
26121
+ * Listen for changes.
26122
+ * @param listener - called after each change.
26123
+ * @returns the unsubscribe.
26124
+ */
26125
+ subscribe(listener) {
26126
+ this.listeners.add(listener);
26127
+ return () => {
26128
+ this.listeners.delete(listener);
26129
+ };
26130
+ }
26131
+ /**
26132
+ * Attach a controller and mirror its store until the returned disposer runs.
26133
+ * @param service - the harness controller.
26134
+ * @returns the detach, which is a no-op once another controller has replaced this one.
26135
+ */
26136
+ attach(service) {
26137
+ this.service = service;
26138
+ const unsubscribe = service.store.subscribe(() => {
26139
+ this.publish();
26140
+ });
26141
+ this.publish();
26142
+ return () => {
26143
+ unsubscribe();
26144
+ if (this.service !== service) return;
26145
+ this.service = void 0;
26146
+ this.publish();
26147
+ };
26148
+ }
26149
+ /**
26150
+ * Record whether the harness's button is currently being shadowed.
26151
+ * @param shadowing - the result of {@link shadowsHarnessSeat} over the live registry.
26152
+ */
26153
+ setShadowing(shadowing) {
26154
+ if (this.shadowing === shadowing) return;
26155
+ this.shadowing = shadowing;
26156
+ this.publish();
26157
+ }
26158
+ /**
26159
+ * Start one session's export through the harness controller.
26160
+ * @param sessionId - the session to export.
26161
+ * @returns false when no controller is attached, so the caller never reports a start that did not happen.
26162
+ */
26163
+ download(sessionId) {
26164
+ if (this.service === void 0) return false;
26165
+ this.service.download(sessionId).catch(() => {});
26166
+ return true;
26167
+ }
26168
+ /**
26169
+ * Close one session's dialog without cancelling the export.
26170
+ * @param sessionId - the session whose dialog closes.
26171
+ */
26172
+ dismiss(sessionId) {
26173
+ this.service?.dismiss(sessionId);
26174
+ }
26175
+ /** Recompute the view and notify, keeping the identity when nothing a reader sees changed. */
26176
+ publish() {
26177
+ const service = this.service;
26178
+ const next = service === void 0 ? DETACHED : {
26179
+ active: this.shadowing,
26180
+ bySession: service.store.getSnapshot().bySession
26181
+ };
26182
+ if (next.active === this.state.active && next.bySession === this.state.bySession) return;
26183
+ this.state = next;
26184
+ for (const listener of [...this.listeners]) listener();
26185
+ }
26186
+ };
26187
+
24049
26188
  //#endregion
24050
26189
  //#region tsbuild/client/target.js
24051
26190
  /**
@@ -24090,11 +26229,13 @@ function resolveTarget(sessions, workspaces, sessionId) {
24090
26229
  * @see {@link HeaderMenuProps}
24091
26230
  */
24092
26231
  function HeaderMenu(props) {
24093
- const { sessionId, useSessions, useWorkspaces, useSettings, useSidebar, t, describe: describe$2 } = props;
26232
+ const { sessionId, useSessions, useWorkspaces, useSettings, useSidebar, useLogDownload, t, describe: describe$2 } = props;
24094
26233
  const bound = useSettings((snapshot) => snapshot.value);
24095
26234
  const sessions = useSessions((state) => state);
24096
26235
  const workspaces = useWorkspaces((state) => state);
24097
26236
  const openPanel = useSidebar((state) => state.panel.panel);
26237
+ const logsActive = useLogDownload((state) => state.active);
26238
+ const logsBusy = useLogDownload((state) => isDownloading(state, String(sessionId)));
24098
26239
  const { view, refresh } = useCapabilityView(describe$2);
24099
26240
  const settings = bound ?? view?.settings;
24100
26241
  const target = (0, react.useMemo)(() => resolveTarget(sessions, workspaces, sessionId), [
@@ -24102,7 +26243,9 @@ function HeaderMenu(props) {
24102
26243
  workspaces,
24103
26244
  sessionId
24104
26245
  ]);
24105
- if (settings === void 0 || !settings.showInSessionHeader) return null;
26246
+ if (settings === void 0) return null;
26247
+ const logsOnly = !settings.showInSessionHeader;
26248
+ if (logsOnly && !logsActive) return null;
24106
26249
  return (0, react_jsx_runtime.jsx)(ActionMenu, {
24107
26250
  target,
24108
26251
  settings,
@@ -24110,7 +26253,47 @@ function HeaderMenu(props) {
24110
26253
  t,
24111
26254
  actions: props,
24112
26255
  refresh,
24113
- openPanel
26256
+ openPanel,
26257
+ logDownload: {
26258
+ active: logsActive,
26259
+ busy: logsBusy
26260
+ },
26261
+ logsOnly
26262
+ });
26263
+ }
26264
+
26265
+ //#endregion
26266
+ //#region tsbuild/client/LogDownloadDialog.js
26267
+ /**
26268
+ * The export dialog for the session this header belongs to.
26269
+ * @param props - the session, the bridged export state, the dismiss callback, and the translator.
26270
+ * @returns the modal portal while this session's dialog is open; nothing otherwise, which leaves no
26271
+ * box in the header row.
26272
+ * @see {@link LogDownloadSeatProps}
26273
+ */
26274
+ function LogDownloadDialog(props) {
26275
+ const { sessionId, useLogDownload, dismiss, t } = props;
26276
+ const active = useLogDownload((view) => view.active);
26277
+ const entry = useLogDownload((view) => view.bySession[String(sessionId)]);
26278
+ if (!active || entry === void 0) return null;
26279
+ const { status } = entry;
26280
+ const close = () => {
26281
+ dismiss(String(sessionId));
26282
+ };
26283
+ const error = status === "error" ? entry.error || t("logs.dialog.commandFailed") : null;
26284
+ const title = status === "downloading" ? t("logs.dialog.preparingTitle") : status === "success" ? t("logs.dialog.successTitle") : t("logs.dialog.errorTitle");
26285
+ const description = status === "downloading" ? t("logs.dialog.preparingDescription") : status === "success" ? t("logs.dialog.successDescription") : error ?? t("logs.dialog.commandFailed");
26286
+ return (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.Modal, {
26287
+ open: entry.open,
26288
+ onClose: close,
26289
+ title,
26290
+ description,
26291
+ closeLabel: t("logs.dialog.close"),
26292
+ footer: (0, react_jsx_runtime.jsx)(__deepseek_ai_dsh_client_ui_primitives.Button, {
26293
+ variant: "primary",
26294
+ onClick: close,
26295
+ children: t("logs.dialog.close")
26296
+ })
24114
26297
  });
24115
26298
  }
24116
26299
 
@@ -24142,9 +26325,19 @@ const zh = {
24142
26325
  "menu.archive": "归档",
24143
26326
  "menu.preview": "预览",
24144
26327
  "menu.delete": "删除",
26328
+ "menu.downloadLog": "下载 Session 日志",
26329
+ "menu.downloadLog.busy": "正在导出",
26330
+ "menu.downloadLog.unavailable": "Session 日志导出当前不可用",
24145
26331
  "menu.empty": "没有可用的操作",
24146
26332
  "menu.noSession": "请先打开一个会话",
24147
26333
  "menu.noDirectory": "该会话没有工作目录",
26334
+ "logs.dialog.preparingTitle": "正在导出 Session",
26335
+ "logs.dialog.preparingDescription": "正在准备包含当前 Session、子 Session 和附件的 ZIP 文件。",
26336
+ "logs.dialog.successTitle": "Session 导出已开始下载",
26337
+ "logs.dialog.successDescription": "浏览器正在下载 Session ZIP 文件。",
26338
+ "logs.dialog.errorTitle": "Session 导出失败",
26339
+ "logs.dialog.close": "关闭",
26340
+ "logs.dialog.commandFailed": "无法启动 Session 导出。",
24148
26341
  "panel.close": "关闭",
24149
26342
  "panel.refresh": "刷新",
24150
26343
  "panel.retry": "重试",
@@ -24270,6 +26463,46 @@ const zh = {
24270
26463
  "preview.noUrl": "这个配置没有可预览的地址",
24271
26464
  "preview.empty": "这个工作区没有启动配置。可以在 .claude/launch.json 中添加,或在设置的 previews 中配置。",
24272
26465
  "preview.emptyFile": "{file} 中没有可用的配置。",
26466
+ "preview.modes": "预览方式",
26467
+ "preview.mode.server": "服务",
26468
+ "preview.mode.file": "文件",
26469
+ "preview.mode.url": "网址",
26470
+ "preview.mode.scratchpad": "草稿",
26471
+ "preview.frame.empty": "这个方式下没有可显示的页面",
26472
+ "preview.viewport.fit": "视口:适应面板",
26473
+ "preview.viewport.custom": "视口:{width} × {height}",
26474
+ "preview.device.custom": "自定义",
26475
+ "preview.inspect": "可检查地打开",
26476
+ "preview.inspectHint": "把这个地址交给网址方式,经主机同源代理打开,从而可以读取其 DOM",
26477
+ "preview.url.field": "要预览的网址",
26478
+ "preview.url.placeholder": "http://127.0.0.1:5173/",
26479
+ "preview.url.go": "打开",
26480
+ "preview.url.reload": "重新加载",
26481
+ "preview.url.proxied": "本机回环地址,已通过主机同源代理打开,可以检查其 DOM 与控制台。",
26482
+ "preview.url.crossOrigin": "这个地址不是本机回环地址,页面会以跨源方式嵌入:可以查看,但无法读取 DOM、控制台或事件。",
26483
+ "preview.url.empty": "输入一个 http(s) 地址。本机回环地址会被代理为同源,因而可以检查。",
26484
+ "preview.file.field": "工作区内的文件",
26485
+ "preview.file.placeholder": "index.html 或 src/app.tsx",
26486
+ "preview.file.open": "预览",
26487
+ "preview.file.empty": "输入一个文件路径,或从文件面板复制一个。",
26488
+ "preview.file.noWorkspace": "这个会话没有工作目录,因此没有可解析的相对路径。",
26489
+ "preview.file.facts": "{name} · {kind} · {bytes}",
26490
+ "preview.file.overLimit": "文件超过 previewMaxFileBytes,无法在面板中预览",
26491
+ "preview.file.notPreviewable": "这个类型无法在面板中渲染;可以用系统默认程序打开。",
26492
+ "preview.file.readFailed": "无法读取文件:{message}",
26493
+ "preview.kind.iframe": "网页",
26494
+ "preview.kind.markdown": "Markdown",
26495
+ "preview.kind.image": "图片",
26496
+ "preview.kind.media": "音视频",
26497
+ "preview.kind.pdf": "PDF",
26498
+ "preview.kind.text": "文本",
26499
+ "preview.kind.other": "未知类型",
26500
+ "preview.scratch.editor": "草稿 HTML",
26501
+ "preview.scratch.render": "重新渲染",
26502
+ "preview.scratch.pending": "正在渲染…",
26503
+ "preview.scratch.saved": "已按工作区保存在此浏览器中",
26504
+ "preview.scratch.unsaved": "浏览器拒绝保存这份草稿(存储已满或被禁用),但渲染仍然有效",
26505
+ "preview.scratch.refused": "主机拒绝了这份草稿文档(HTTP {status})",
24273
26506
  "delete.title": "删除会话",
24274
26507
  "delete.body.archive": "“{name}” 将从侧边栏中隐藏,会话记录会保留在磁盘上。",
24275
26508
  "delete.body.purge": "“{name}” 将被隐藏,其会话记录文件也会被删除。此操作无法撤销。",
@@ -24282,7 +26515,7 @@ const zh = {
24282
26515
  "notice.dismiss": "关闭提示",
24283
26516
  "error.transport": "主机没有响应:{message}",
24284
26517
  "settings.title": "高级侧边栏",
24285
- "settings.description": "侧边栏的文件更改、终端、文件、后台任务、打开方式、归档与删除操作",
26518
+ "settings.description": "对话旁的文件更改、终端、文件、预览、后台任务、打开方式、归档与删除操作",
24286
26519
  "settings.status.ready": "可用",
24287
26520
  "settings.status.partial": "部分可用",
24288
26521
  "settings.group.placement": "入口",
@@ -24314,7 +26547,7 @@ const zh = {
24314
26547
  "settings.previewReadyTimeoutMs": "预览就绪超时",
24315
26548
  "settings.previewReadyTimeoutMs.hint": "等待端口开始接受连接的时间上限(毫秒)。",
24316
26549
  "settings.previews": "预览配置",
24317
- "settings.previews.hint": "在 cordis.yml 的 previews 中配置;工作区的 .claude/launch.json 会追加在前。",
26550
+ "settings.previews.hint": "在 cordis.patch.yml 的 previews 中配置;工作区的 .claude/launch.json 会追加在前。",
24318
26551
  "settings.previews.empty": "没有配置预览。",
24319
26552
  "settings.panelWidth": "面板宽度",
24320
26553
  "settings.panelWidth.hint": "抽屉的宽度(像素);窗口较窄时会自动收窄。",
@@ -24322,7 +26555,7 @@ const zh = {
24322
26555
  "settings.deleteMode.archive": "仅归档",
24323
26556
  "settings.deleteMode.purge": "归档并删除记录",
24324
26557
  "settings.deleteMode.hint": "“归档并删除记录”会移除会话记录文件,无法撤销;正在运行的会话只会被归档。",
24325
- "settings.deleteMode.unsupported": "当前的会话存储后端没有单独的会话文件,因此只能归档。",
26558
+ "settings.deleteMode.unsupported": "当前 harness 不支持删除会话记录,因此只能归档。",
24326
26559
  "settings.confirmDelete": "删除前确认",
24327
26560
  "settings.confirmDelete.hint": "选择“归档并删除记录”时必须开启。",
24328
26561
  "settings.allowTaskKill": "允许停止后台任务",
@@ -24352,7 +26585,7 @@ const zh = {
24352
26585
  "settings.maxTerminals": "最多同时打开的终端",
24353
26586
  "settings.maxTerminals.hint": "面板终端的并发上限。",
24354
26587
  "settings.editors": "打开方式目标",
24355
- "settings.editors.hint": "在 cordis.yml 的 editors 中配置;此处显示它们在本机是否可用。",
26588
+ "settings.editors.hint": "在 cordis.patch.yml 的 editors 中配置;此处显示它们在本机是否可用。",
24356
26589
  "settings.editors.empty": "没有配置外部程序。",
24357
26590
  "settings.editors.available": "可用",
24358
26591
  "settings.editors.missing": "未找到",
@@ -24372,9 +26605,19 @@ const en = {
24372
26605
  "menu.archive": "Archive",
24373
26606
  "menu.preview": "Preview",
24374
26607
  "menu.delete": "Delete",
26608
+ "menu.downloadLog": "Download session log",
26609
+ "menu.downloadLog.busy": "Exporting",
26610
+ "menu.downloadLog.unavailable": "Session log export is not available right now",
24375
26611
  "menu.empty": "No actions are available",
24376
26612
  "menu.noSession": "Open a session first",
24377
26613
  "menu.noDirectory": "This session has no working directory",
26614
+ "logs.dialog.preparingTitle": "Exporting Session",
26615
+ "logs.dialog.preparingDescription": "Preparing a ZIP containing this Session, its sub-Sessions, and attachments.",
26616
+ "logs.dialog.successTitle": "Session download started",
26617
+ "logs.dialog.successDescription": "The browser is downloading the Session ZIP.",
26618
+ "logs.dialog.errorTitle": "Session export failed",
26619
+ "logs.dialog.close": "Close",
26620
+ "logs.dialog.commandFailed": "Could not start the Session export.",
24378
26621
  "panel.close": "Close",
24379
26622
  "panel.refresh": "Refresh",
24380
26623
  "panel.retry": "Retry",
@@ -24500,6 +26743,46 @@ const en = {
24500
26743
  "preview.noUrl": "This configuration has no address to preview",
24501
26744
  "preview.empty": "This workspace has no launch configurations. Add one to .claude/launch.json, or configure `previews` in settings.",
24502
26745
  "preview.emptyFile": "{file} carries no usable configurations.",
26746
+ "preview.modes": "Preview mode",
26747
+ "preview.mode.server": "Server",
26748
+ "preview.mode.file": "File",
26749
+ "preview.mode.url": "URL",
26750
+ "preview.mode.scratchpad": "Scratchpad",
26751
+ "preview.frame.empty": "Nothing is framed in this mode yet",
26752
+ "preview.viewport.fit": "Viewport: fit the panel",
26753
+ "preview.viewport.custom": "Viewport: {width} × {height}",
26754
+ "preview.device.custom": "Custom",
26755
+ "preview.inspect": "Open inspectable",
26756
+ "preview.inspectHint": "Hand this address to the URL mode, proxied same-origin, so its DOM can be read",
26757
+ "preview.url.field": "Address to preview",
26758
+ "preview.url.placeholder": "http://127.0.0.1:5173/",
26759
+ "preview.url.go": "Open",
26760
+ "preview.url.reload": "Reload",
26761
+ "preview.url.proxied": "Loopback address, proxied through this Host so the frame is same-origin and its DOM and console are readable.",
26762
+ "preview.url.crossOrigin": "This is not a loopback address, so the page is framed cross-origin: you can look at it, but its DOM, console and events cannot be read.",
26763
+ "preview.url.empty": "Type an http(s) address. A loopback address is proxied same-origin, which is what makes it inspectable.",
26764
+ "preview.file.field": "File inside the workspace",
26765
+ "preview.file.placeholder": "index.html or src/app.tsx",
26766
+ "preview.file.open": "Preview",
26767
+ "preview.file.empty": "Type a file path, or copy one from the Files panel.",
26768
+ "preview.file.noWorkspace": "This session has no working directory, so there is nothing for a relative path to resolve against.",
26769
+ "preview.file.facts": "{name} · {kind} · {bytes}",
26770
+ "preview.file.overLimit": "The file is over previewMaxFileBytes, so it cannot be previewed in the panel",
26771
+ "preview.file.notPreviewable": "This type cannot be rendered in the panel; open it with the operating system’s default application.",
26772
+ "preview.file.readFailed": "The file could not be read: {message}",
26773
+ "preview.kind.iframe": "document",
26774
+ "preview.kind.markdown": "Markdown",
26775
+ "preview.kind.image": "image",
26776
+ "preview.kind.media": "audio/video",
26777
+ "preview.kind.pdf": "PDF",
26778
+ "preview.kind.text": "text",
26779
+ "preview.kind.other": "unknown type",
26780
+ "preview.scratch.editor": "Scratchpad HTML",
26781
+ "preview.scratch.render": "Render",
26782
+ "preview.scratch.pending": "Rendering…",
26783
+ "preview.scratch.saved": "Saved in this browser, per workspace",
26784
+ "preview.scratch.unsaved": "This browser refused to save the scratchpad (storage full or disabled); rendering still works",
26785
+ "preview.scratch.refused": "The Host refused the scratchpad document (HTTP {status})",
24503
26786
  "delete.title": "Delete session",
24504
26787
  "delete.body.archive": "“{name}” will be hidden from the sidebar. Its log stays on disk.",
24505
26788
  "delete.body.purge": "“{name}” will be hidden and its session log file removed. This cannot be undone.",
@@ -24512,7 +26795,7 @@ const en = {
24512
26795
  "notice.dismiss": "Dismiss",
24513
26796
  "error.transport": "The Host did not answer: {message}",
24514
26797
  "settings.title": "Advanced sidebar",
24515
- "settings.description": "Changes, terminal, files, background tasks, Open in, Archive and Delete on the sidebar",
26798
+ "settings.description": "Changes, terminal, files, preview, background tasks, Open in, Archive and Delete beside the conversation",
24516
26799
  "settings.status.ready": "Ready",
24517
26800
  "settings.status.partial": "Partly available",
24518
26801
  "settings.group.placement": "Where it appears",
@@ -24544,7 +26827,7 @@ const en = {
24544
26827
  "settings.previewReadyTimeoutMs": "Preview ready timeout",
24545
26828
  "settings.previewReadyTimeoutMs.hint": "How long to wait for the port to start accepting, in milliseconds.",
24546
26829
  "settings.previews": "Preview configurations",
24547
- "settings.previews.hint": "Configured under `previews` in cordis.yml; a workspace’s own .claude/launch.json is read first.",
26830
+ "settings.previews.hint": "Configured under `previews` in cordis.patch.yml; a workspace’s own .claude/launch.json is read first.",
24548
26831
  "settings.previews.empty": "No preview configurations.",
24549
26832
  "settings.panelWidth": "Panel width",
24550
26833
  "settings.panelWidth.hint": "Drawer width in pixels; a narrow window shrinks it.",
@@ -24552,7 +26835,7 @@ const en = {
24552
26835
  "settings.deleteMode.archive": "Archive only",
24553
26836
  "settings.deleteMode.purge": "Archive and remove the log",
24554
26837
  "settings.deleteMode.hint": "Removing the log cannot be undone; a live session is archived only.",
24555
- "settings.deleteMode.unsupported": "This session-persistence backend keeps no per-session file, so Delete can only archive.",
26838
+ "settings.deleteMode.unsupported": "This harness has no supported way to remove a session log, so Delete can only archive.",
24556
26839
  "settings.confirmDelete": "Confirm before deleting",
24557
26840
  "settings.confirmDelete.hint": "Required while Delete removes the log.",
24558
26841
  "settings.allowTaskKill": "Allow stopping a task",
@@ -24582,7 +26865,7 @@ const en = {
24582
26865
  "settings.maxTerminals": "Most terminals at once",
24583
26866
  "settings.maxTerminals.hint": "How many panel terminals may be open together.",
24584
26867
  "settings.editors": "Open in targets",
24585
- "settings.editors.hint": "Configured under `editors` in cordis.yml; this lists whether each resolves on this Host.",
26868
+ "settings.editors.hint": "Configured under `editors` in cordis.patch.yml; this lists whether each resolves on this Host.",
24586
26869
  "settings.editors.empty": "No external applications are configured.",
24587
26870
  "settings.editors.available": "Available",
24588
26871
  "settings.editors.missing": "Not found",
@@ -24633,6 +26916,7 @@ async function apply(ctx) {
24633
26916
  */
24634
26917
  function surface(ctx) {
24635
26918
  const controller = new PanelController();
26919
+ const logDownload = new LogDownloadBridge();
24636
26920
  const unwrap = (result) => {
24637
26921
  if (!result.ok) throw new Error(`${result.error.message} (${result.error.code})`);
24638
26922
  return result.value;
@@ -24723,7 +27007,8 @@ function surface(ctx) {
24723
27007
  const menuInjected = () => ({
24724
27008
  hooks: {
24725
27009
  sidebar: controller,
24726
- settings: scope
27010
+ settings: scope,
27011
+ logDownload
24727
27012
  },
24728
27013
  describe: describe$2,
24729
27014
  openPanel: (panel, target) => {
@@ -24734,7 +27019,52 @@ function surface(ctx) {
24734
27019
  window.open(window.location.href, "_blank", "noopener,noreferrer");
24735
27020
  },
24736
27021
  archive,
24737
- requestDelete
27022
+ requestDelete,
27023
+ downloadLog: (sessionId) => {
27024
+ if (!logDownload.download(sessionId)) controller.notify("error", ctx.locale.bind(LOCALE_NS)("menu.downloadLog.unavailable"));
27025
+ }
27026
+ });
27027
+ /**
27028
+ * Download session log, absorbed from `@deepseek-ai/dsh-session-log-export` (see
27029
+ * `log-download.ts` for the whole rationale).
27030
+ *
27031
+ * Its own child fiber, injecting the harness's `sessionLogDownload` service, because that service
27032
+ * is optional and may arrive after this plugin: Cordis applies the child once the service exists
27033
+ * and disposes it when the service goes, so the menu loads either way, and the shadow and the
27034
+ * bridge exist exactly while there is a controller behind them. The service is then read through
27035
+ * `ctx.get` and narrowed by shape, since its type belongs to a package this one does not depend on.
27036
+ */
27037
+ ctx.plugin({
27038
+ name: "advanced-sidebar-log-download",
27039
+ inject: ["slots", LOG_DOWNLOAD_SERVICE],
27040
+ apply: (child) => {
27041
+ const service = asLogDownloadService(child.get(LOG_DOWNLOAD_SERVICE));
27042
+ if (service === void 0) return;
27043
+ child.effect(() => logDownload.attach(service), "advanced-sidebar: session log export bridge");
27044
+ child.effect(() => {
27045
+ const recheck = () => {
27046
+ logDownload.setShadowing(shadowsHarnessSeat(child.slots.entries(LOG_DOWNLOAD_SLOT)));
27047
+ };
27048
+ recheck();
27049
+ const unsubscribe = child.slots.subscribe(LOG_DOWNLOAD_SLOT, recheck);
27050
+ return () => {
27051
+ unsubscribe();
27052
+ logDownload.setShadowing(false);
27053
+ };
27054
+ }, "advanced-sidebar: session log download seat watch");
27055
+ child.slots.inject(LOG_DOWNLOAD_SLOT, () => child.slots.register({
27056
+ name: LOG_DOWNLOAD_SLOT,
27057
+ id: LOG_DOWNLOAD_SEAT_ID,
27058
+ priority: LOG_DOWNLOAD_SHADOW_PRIORITY,
27059
+ locale: LOCALE_NS,
27060
+ inject: () => ({
27061
+ hooks: { logDownload },
27062
+ dismiss: (sessionId) => {
27063
+ logDownload.dismiss(sessionId);
27064
+ }
27065
+ })
27066
+ }, LogDownloadDialog));
27067
+ }
24738
27068
  });
24739
27069
  ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
24740
27070
  name: "conversation.session.header.utilities",
@@ -24808,6 +27138,13 @@ function surface(ctx) {
24808
27138
  serverId,
24809
27139
  fromOffset
24810
27140
  }).then(unwrap),
27141
+ previewFileInfo: (workspacePath, path, signal) => remote.previewFileInfo({
27142
+ workspacePath,
27143
+ path
27144
+ }, signal).then(unwrap),
27145
+ previewPoll: (request) => remote.previewPoll(request).then(unwrap),
27146
+ previewResult: (request) => remote.previewResult(request).then(unwrap),
27147
+ previewRelease: (clientId) => remote.previewRelease({ clientId }).then(unwrap),
24811
27148
  readFile: (path, workspacePath, signal) => remote.readFile({
24812
27149
  path,
24813
27150
  workspacePath