@artenx/dshb 0.1.9 → 0.1.11

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 (39) hide show
  1. package/lib/client.js +56 -90
  2. package/lib/client.js.map +1 -1
  3. package/lib/core/index.js +5 -1
  4. package/lib/core/index.js.map +1 -1
  5. package/lib/core/routes.d.ts +8 -1
  6. package/lib/core/routes.js +65 -3
  7. package/lib/core/routes.js.map +1 -1
  8. package/lib/core/workspace-bindings.js +6 -4
  9. package/lib/core/workspace-bindings.js.map +1 -1
  10. package/lib/exec-docker/daemon-runner.js +2 -2
  11. package/lib/exec-docker/docker-backend.d.ts +8 -0
  12. package/lib/exec-docker/docker-client.d.ts +9 -0
  13. package/lib/exec-docker/docker-client.js +10 -2
  14. package/lib/exec-docker/docker-client.js.map +1 -1
  15. package/lib/exec-docker/docker-routes.js +1 -1
  16. package/lib/exec-docker/fs-provider.d.ts +3 -12
  17. package/lib/exec-docker/fs-provider.js +19 -2
  18. package/lib/exec-docker/fs-provider.js.map +1 -1
  19. package/lib/exec-docker/index.js +1 -1
  20. package/lib/exec-docker/remote-docker-cli.d.ts +8 -0
  21. package/lib/exec-docker/remote-docker-cli.js +27 -1
  22. package/lib/exec-docker/remote-docker-cli.js.map +1 -1
  23. package/lib/exec-docker/world.d.ts +1 -1
  24. package/lib/exec-ssh/executor.d.ts +7 -0
  25. package/lib/exec-ssh/executor.js +18 -0
  26. package/lib/exec-ssh/executor.js.map +1 -1
  27. package/lib/exec-ssh/fs-provider.d.ts +3 -12
  28. package/lib/exec-ssh/fs-provider.js +20 -3
  29. package/lib/exec-ssh/fs-provider.js.map +1 -1
  30. package/lib/exec-ssh/world.d.ts +1 -1
  31. package/lib/router/decorate-fs.js +16 -2
  32. package/lib/router/decorate-fs.js.map +1 -1
  33. package/lib/router/decorate-shell.d.ts +1 -1
  34. package/lib/router/index.d.ts +1 -1
  35. package/lib/router/resolve.d.ts +1 -1
  36. package/lib/router/router-fs.d.ts +1 -1
  37. package/lib/router/types.d.ts +1 -1
  38. package/lib/{types-ekJQQ4x6.d.ts → types-DPP05ZsA.d.ts} +2 -2
  39. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -445,7 +445,7 @@ window.__ModuleLoader__.load({
445
445
  get: () => true
446
446
  });
447
447
  ctx.plugin({
448
- inject: ["slots", "settingsScope"],
448
+ inject: ["slots"],
449
449
  apply: (sub) => {
450
450
  sub.slots.inject("settings.section", () => sub.slots.register({
451
451
  name: "settings.section",
@@ -539,7 +539,7 @@ window.__ModuleLoader__.load({
539
539
  const res = await fetch("/api/dshb/nodes");
540
540
  if (!res.ok) return;
541
541
  const data = await res.json();
542
- setNodes((data.nodes ?? []).filter((n) => n.type === "local-host" || n.status?.reachable === true));
542
+ setNodes(data.nodes ?? []);
543
543
  } catch {}
544
544
  })();
545
545
  }, [props.open]);
@@ -1555,72 +1555,36 @@ window.__ModuleLoader__.load({
1555
1555
  "overflow-y",
1556
1556
  "box-sizing"
1557
1557
  ];
1558
- /**
1559
- * 把挂在 composer 内部的绝对定位浮层统一改造成 position:fixed 视口级浮层:
1560
- * 水平居中(左右各留 8px,绝不贴边/溢出),高度按视口比例封顶并内容滚动,
1561
- * 触发元素上方空间足够则向上展开、否则向下展开,四边都约束在视口内。
1562
- * fixed 不受祖先 overflow 裁剪(祖先带 transform 时失效)。
1563
- */
1564
- function positionFixedSheet(el, rootRect, maxWidth, maxHeightRatio) {
1558
+ /** Keep the model menu anchored to its trigger while fitting it in the viewport. */
1559
+ function positionAnchoredMenu(el, triggerRect, maxWidth, maxHeight) {
1565
1560
  const margin = 8;
1566
1561
  const vw = window.innerWidth;
1567
1562
  const vh = window.innerHeight;
1568
- const width = Math.max(0, Math.min(maxWidth, vw - 16));
1569
- const left = Math.round((vw - width) / 2);
1570
- const maxH = Math.round(vh * maxHeightRatio);
1571
- const spaceAbove = rootRect.top - margin;
1572
- const spaceBelow = vh - rootRect.bottom - margin;
1573
- const expandUp = spaceAbove >= 140 && spaceAbove >= spaceBelow;
1574
- let top;
1575
- if (expandUp) {
1576
- const h = Math.min(maxH, Math.max(spaceAbove, 140));
1577
- top = rootRect.top - margin - h;
1578
- } else top = rootRect.bottom + margin;
1579
- top = Math.max(margin, top);
1580
- el.style.setProperty("position", "fixed", "important");
1581
- el.style.setProperty("box-sizing", "border-box", "important");
1582
- el.style.setProperty("width", `${width}px`, "important");
1583
- el.style.setProperty("left", `${left}px`, "important");
1584
- el.style.setProperty("right", "auto", "important");
1585
- el.style.setProperty("top", `${top}px`, "important");
1586
- el.style.setProperty("bottom", "auto", "important");
1587
- el.style.setProperty("min-width", "0", "important");
1588
- el.style.setProperty("max-width", "none", "important");
1589
- el.style.setProperty("max-height", `${maxH}px`, "important");
1590
- el.style.setProperty("overflow-y", "auto", "important");
1591
- }
1592
- /**
1593
- * 一级 pane(Model/Effort 单元格小菜单)紧凑浮层:右缘对齐触发按钮右缘
1594
- * (面板右缘 x = 按钮右缘 x,钳制在视口内 8px 起,避免宽面板超出屏幕左缘时
1595
- * 被甩到左边贴边),向上展开、空间不足向下展开;宽度跟随内容
1596
- * (max-content,封顶 min(420, vw-16)),避免小菜单被全宽 sheet 拉远到
1597
- * 屏幕中间。测量与定位在同一任务内同步完成,无闪烁。
1598
- */
1599
- function positionCompactPanel(el, root, rootRect) {
1600
- const margin = 8;
1601
- const vw = window.innerWidth;
1602
- const trigger = root.querySelector("[class*=\"7KE1Ra_trigger\"], [class*=\"_trigger\"]") ?? root;
1603
- const anchorRect = trigger === root ? rootRect : trigger.getBoundingClientRect();
1604
1563
  el.style.setProperty("position", "fixed", "important");
1605
1564
  el.style.setProperty("box-sizing", "border-box", "important");
1606
1565
  el.style.setProperty("left", "0", "important");
1607
- el.style.setProperty("top", "0", "important");
1608
1566
  el.style.setProperty("right", "auto", "important");
1567
+ el.style.setProperty("top", "0", "important");
1609
1568
  el.style.setProperty("bottom", "auto", "important");
1610
- el.style.setProperty("width", "max-content", "important");
1611
1569
  el.style.setProperty("min-width", "0", "important");
1612
- el.style.setProperty("max-width", `${Math.min(420, vw - 16)}px`, "important");
1613
- el.style.setProperty("max-height", "none", "important");
1614
- el.style.setProperty("overflow-y", "visible", "important");
1615
- const w = el.offsetWidth;
1616
- const h = el.offsetHeight;
1617
- const panelRightX = Math.min(anchorRect.right, vw - margin);
1618
- const expandUp = anchorRect.top - margin - h >= margin;
1619
- const top = Math.max(margin, expandUp ? anchorRect.top - margin - h : anchorRect.bottom + margin);
1620
- const left = Math.max(margin, panelRightX - w);
1570
+ el.style.setProperty("max-width", `${Math.max(0, Math.min(maxWidth, vw - 16))}px`, "important");
1571
+ el.style.setProperty("max-height", `${Math.max(0, Math.min(maxHeight, vh - 16))}px`, "important");
1572
+ el.style.setProperty("overflow-y", "auto", "important");
1573
+ let width = el.offsetWidth;
1574
+ let height = el.offsetHeight;
1575
+ const spaceAbove = Math.max(0, triggerRect.top - 16);
1576
+ const spaceBelow = Math.max(0, vh - triggerRect.bottom - 16);
1577
+ const expandUp = height <= spaceAbove || spaceAbove >= spaceBelow;
1578
+ const available = expandUp ? spaceAbove : spaceBelow;
1579
+ if (height > available) {
1580
+ el.style.setProperty("max-height", `${Math.max(0, available - margin)}px`, "important");
1581
+ height = el.offsetHeight;
1582
+ width = el.offsetWidth;
1583
+ }
1584
+ const top = expandUp ? triggerRect.top - margin - height : triggerRect.bottom + margin;
1585
+ const left = Math.max(margin, Math.min(triggerRect.right - width, vw - width - margin));
1621
1586
  el.style.setProperty("left", `${left}px`, "important");
1622
- el.style.setProperty("top", `${top}px`, "important");
1623
- el.style.setProperty("width", `${w}px`, "important");
1587
+ el.style.setProperty("top", `${Math.max(margin, Math.min(top, vh - height - margin))}px`, "important");
1624
1588
  }
1625
1589
  /**
1626
1590
  * 模型名多为纯连字符词(DeepSeek-V4-Flash-Vision-Exp);white-space:normal 下
@@ -1673,7 +1637,7 @@ window.__ModuleLoader__.load({
1673
1637
  n.style.removeProperty("font-size");
1674
1638
  }
1675
1639
  }
1676
- /** 清除 positionFixedSheet 写入的内联样式,交还上游/移动端 CSS 兜底。 */
1640
+ /** 清除 anchored menu 写入的内联样式,交还上游 CSS。 */
1677
1641
  function clearFixedSheet(el) {
1678
1642
  if (el === null || el === void 0) return;
1679
1643
  for (const key of SHEET_PROPS) el.style.removeProperty(key);
@@ -1683,10 +1647,8 @@ window.__ModuleLoader__.load({
1683
1647
  * 元素:一级 Model/Effort 单元格列表(cellLabel),点击后切到模型列表(modelName)
1684
1648
  * 或档位列表。上游默认 `position:absolute;right:0` 贴触发按钮右缘,触发按钮在
1685
1649
  * 可横向滚动的 stats 行内时菜单会整体出屏。两级 pane 都必须接管(不能只按
1686
- * modelName 匹配,否则一级 pane 漏掉)。窄屏下:一级小菜单走紧凑浮层
1687
- * (右缘贴按钮、向上展开,避免全宽 sheet 把小菜单拉到屏幕中间离按钮太远);
1688
- * 二级列表走视口级居中 fixed sheet(左右各 8px、高度 45% 视口封顶、
1689
- * 内容滚动、上方空间不足时向下展开)。
1650
+ * modelName 匹配,否则一级 pane 漏掉)。所有视口都把菜单锚定到触发按钮,
1651
+ * 在上方/下方可用空间中选择更合适的一侧,避免上游空间不足时把菜单钳到屏幕顶端。
1690
1652
  */
1691
1653
  function installModelMenuPosition(ctx) {
1692
1654
  ctx.effect(() => {
@@ -1706,37 +1668,41 @@ window.__ModuleLoader__.load({
1706
1668
  let fittedVw = 0;
1707
1669
  let fittedSig = -1;
1708
1670
  let fittedMenus = [];
1671
+ let positionedMenus = [];
1709
1672
  const sync = () => {
1710
1673
  const menus = findMenus();
1711
- if (!narrow.matches) {
1712
- if (fittedMenus.length > 0) {
1713
- for (const menu of fittedMenus) {
1714
- clearFixedSheet(menu);
1715
- clearModelNameFit(menu);
1716
- }
1717
- fittedVw = 0;
1718
- fittedSig = -1;
1719
- fittedMenus = [];
1720
- window.dispatchEvent(new Event("resize"));
1721
- }
1722
- return;
1723
- }
1724
1674
  let vw = 0;
1725
1675
  let sig = 0;
1726
1676
  const modelMenus = [];
1677
+ const visibleMenus = [];
1727
1678
  for (const menu of menus) {
1728
1679
  const trigger = findTrigger(menu);
1729
- if (trigger === null) continue;
1680
+ if (trigger === null || trigger.getAttribute("aria-expanded") !== "true") continue;
1730
1681
  const rect = menu.getBoundingClientRect();
1731
1682
  if (rect.width === 0 && rect.height === 0) continue;
1732
- const triggerRect = trigger.getBoundingClientRect();
1683
+ positionAnchoredMenu(menu, trigger.getBoundingClientRect(), Math.min(420, window.innerWidth - 16), 360);
1684
+ visibleMenus.push(menu);
1733
1685
  if (menu.querySelector("[class*=\"modelName\"]")) {
1734
- positionFixedSheet(menu, triggerRect, Number.POSITIVE_INFINITY, .45);
1735
- applyNonBreakingHyphens(menu);
1736
1686
  modelMenus.push(menu);
1737
- vw = window.innerWidth;
1738
- for (const n of menu.querySelectorAll("[class*=\"modelName\"]")) sig += n.textContent?.length ?? 0;
1739
- } else positionCompactPanel(menu, trigger, triggerRect);
1687
+ if (narrow.matches) {
1688
+ applyNonBreakingHyphens(menu);
1689
+ vw = window.innerWidth;
1690
+ for (const n of menu.querySelectorAll("[class*=\"modelName\"]")) sig += n.textContent?.length ?? 0;
1691
+ }
1692
+ }
1693
+ }
1694
+ for (const previous of positionedMenus) {
1695
+ if (visibleMenus.includes(previous)) continue;
1696
+ clearFixedSheet(previous);
1697
+ clearModelNameFit(previous);
1698
+ }
1699
+ positionedMenus = visibleMenus;
1700
+ if (!narrow.matches) {
1701
+ for (const menu of modelMenus) clearModelNameFit(menu);
1702
+ fittedVw = 0;
1703
+ fittedSig = -1;
1704
+ fittedMenus = [];
1705
+ return;
1740
1706
  }
1741
1707
  const needFit = modelMenus.some((m) => !fittedMenus.includes(m));
1742
1708
  if (vw > 0 && (needFit || vw !== fittedVw || sig !== fittedSig)) {
@@ -2350,11 +2316,9 @@ window.__ModuleLoader__.load({
2350
2316
  if (selectedId === "new") return;
2351
2317
  setBusy(true);
2352
2318
  try {
2353
- const node = nodes.find((n) => n.id === selectedId);
2354
- if (node && (node.type === "local-docker" || node.type === "remote-docker") && node.docker?.containerId) try {
2355
- await fetch(`/api/dshb/docker/${selectedId}/delete`, { method: "POST" });
2356
- } catch {}
2357
- if ((await fetch(`/api/dshb/nodes/${selectedId}`, { method: "DELETE" })).ok) {
2319
+ const res = await fetch(`/api/dshb/nodes/${selectedId}`, { method: "DELETE" });
2320
+ const data = await res.json();
2321
+ if (res.ok && data.ok) {
2358
2322
  flash({
2359
2323
  kind: "ok",
2360
2324
  text: "节点已删除"
@@ -2362,7 +2326,10 @@ window.__ModuleLoader__.load({
2362
2326
  setSelectedId("new");
2363
2327
  setForm(EMPTY_FORM);
2364
2328
  reload();
2365
- }
2329
+ } else flash({
2330
+ kind: "error",
2331
+ text: data.error ?? "删除失败"
2332
+ });
2366
2333
  } catch {
2367
2334
  flash({
2368
2335
  kind: "error",
@@ -2373,7 +2340,6 @@ window.__ModuleLoader__.load({
2373
2340
  }
2374
2341
  }, [
2375
2342
  selectedId,
2376
- nodes,
2377
2343
  flash,
2378
2344
  reload
2379
2345
  ]);