dsh-stall-guard 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/client.js +36 -8
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@
5
5
  格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
6
6
  版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
7
7
 
8
+ ## [0.1.3] - 2026-10-21
9
+
10
+ ### 修复
11
+
12
+ - **拖动图标会带动上方状态栏**:浮动态原先仍渲染在标题栏槽位里,那个槽位是正常文档流
13
+ 中的 flex 项,`position:fixed` 在那里无效,图标移动时会把整行撑动。
14
+ 现在浮动态改由 `shell.overlay` 渲染(真正脱离所有列与滚动容器),标题栏在浮动时
15
+ 渲染空。这样图标可以像贴纸一样拖到任意位置,不影响任何其他元素。
16
+ - **调整大小时看不到实时预览**:设置面板原先从 `top:56px` 开始展开,正好压住标题栏
17
+ 上的图标,所以拖滑块时看不到尺寸变化。面板改为从标题栏下方开始(`top:118px`)。
18
+ - 浮动态的层级提到面板之上(`z-index:75`),即使图标被拖到面板范围内也仍然可见可拖。
19
+ - 拖动位置改从 store 读取而不是每帧读 localStorage,避免高频拖动时状态竞争、
20
+ 丢中间位置。
21
+
8
22
  ## [0.1.2] - 2026-10-21
9
23
 
10
24
  ### 修复
package/client.js CHANGED
@@ -955,7 +955,7 @@ window.__ModuleLoader__.load({
955
955
  /* Hidden state: the bubble is not rendered at all, so there is nothing to dim. */
956
956
 
957
957
  /* ---- overlay panel ---- */
958
- '.dsg-panel{position:fixed;top:56px;right:14px;left:auto;z-index:70;box-sizing:border-box;width:min(430px,calc(100vw - 40px));max-height:min(74vh,660px);overflow:hidden;pointer-events:auto;display:flex;flex-direction:column;gap:0;padding:12px;border:1px solid var(--dsw-alias-border-l1,var(--dsh-border,rgba(255,255,255,.12)));border-radius:var(--dsw-radius-panel,12px);background:var(--dsw-alias-bg-overlay,var(--dsh-surface,rgba(20,22,28,.96)));box-shadow:var(--dsw-elevation-soft,0 8px 28px rgba(0,0,0,.22));color:var(--dsw-alias-label-primary,var(--dsh-text-primary,#e6e6e6));font:inherit;font-size:12px;line-height:18px}',
958
+ '.dsg-panel{position:fixed;top:118px;right:14px;left:auto;z-index:70;box-sizing:border-box;width:min(430px,calc(100vw - 40px));max-height:min(74vh,660px);overflow:hidden;pointer-events:auto;display:flex;flex-direction:column;gap:0;padding:12px;border:1px solid var(--dsw-alias-border-l1,var(--dsh-border,rgba(255,255,255,.12)));border-radius:var(--dsw-radius-panel,12px);background:var(--dsw-alias-bg-overlay,var(--dsh-surface,rgba(20,22,28,.96)));box-shadow:var(--dsw-elevation-soft,0 8px 28px rgba(0,0,0,.22));color:var(--dsw-alias-label-primary,var(--dsh-text-primary,#e6e6e6));font:inherit;font-size:12px;line-height:18px}',
959
959
  '.dsg-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;flex:0 0 auto;padding-bottom:8px}',
960
960
  /* The title bar holds Save and Close now, so the title must not push them out. */
961
961
  '.dsg-title{flex:0 1 auto;min-width:0;margin:0;font-size:13px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}',
@@ -1040,7 +1040,7 @@ window.__ModuleLoader__.load({
1040
1040
  '.dsg-offTab{display:block;width:100%;height:100%;border-radius:50%}',
1041
1041
  '.dsg-orb[data-floating="yes"]{box-shadow:0 2px 10px rgba(0,0,0,.28);background:var(--dsw-alias-bg-overlay,var(--dsh-surface,rgba(20,22,28,.9)));border:1px solid var(--dsw-alias-border-l1,var(--dsh-border,rgba(255,255,255,.12)))}',
1042
1042
  '.dsg-orb[data-dragging="yes"]{transition:none!important;cursor:grabbing}',
1043
- '.dsg-seat[data-floating="yes"]{position:fixed}',
1043
+ '.dsg-seat[data-floating="yes"]{position:fixed;z-index:75}',
1044
1044
  /* Only visible while the supervisor is hidden: a 14px grab handle in the corner. */
1045
1045
  '.dsg-restoreTab{position:fixed;right:10px;bottom:10px;z-index:67;width:14px;height:14px;padding:0;border:1px solid var(--dsw-alias-border-l1,var(--dsh-border,rgba(255,255,255,.2)));border-radius:50%;background:var(--dsw-alias-label-tertiary,var(--dsh-text-muted,#8b93a7));opacity:.4;cursor:pointer;transition:opacity .15s ease,transform .15s ease}',
1046
1046
  '.dsg-restoreTab:hover,.dsg-restoreTab:focus-visible{opacity:1;transform:scale(1.35);background:var(--dsw-alias-brand-primary,var(--dsh-accent,#4d6bfe))}',
@@ -1238,7 +1238,8 @@ window.__ModuleLoader__.load({
1238
1238
 
1239
1239
  /* Float placement: drag moves the control, and the position is clamped into the
1240
1240
  * viewport on release so a window resize cannot strand it off-screen. */
1241
- const floating = appearance.place === 'float';
1241
+ // The overlay seat forces the floating posture; the header seat reads the setting.
1242
+ const floating = props.forcePlace === 'float' || appearance.place === 'float';
1242
1243
  const startDrag = useCallback((event) => {
1243
1244
  if (!floating) return;
1244
1245
  if (event.button !== undefined && event.button !== 0) return;
@@ -1254,7 +1255,9 @@ window.__ModuleLoader__.load({
1254
1255
  setDragging(true);
1255
1256
  const nextX = Math.max(0, Math.min(window.innerWidth - rect.width, moveEvent.clientX - offsetX));
1256
1257
  const nextY = Math.max(0, Math.min(window.innerHeight - rect.height, moveEvent.clientY - offsetY));
1257
- store.setAppearance({ ...readAppearance(), x: Math.round(nextX), y: Math.round(nextY) });
1258
+ // Read from the store, not localStorage: a per-frame disk read would race with
1259
+ // the in-memory value and drop intermediate positions.
1260
+ store.setAppearance({ ...store.getAppearance(), x: Math.round(nextX), y: Math.round(nextY) });
1258
1261
  };
1259
1262
  const onUp = () => {
1260
1263
  window.removeEventListener('pointermove', onMove);
@@ -1267,10 +1270,10 @@ window.__ModuleLoader__.load({
1267
1270
  event.preventDefault();
1268
1271
  }, [floating]);
1269
1272
 
1270
- // Hidden: the header renders nothing. A restore tab is drawn by the overlay seat
1271
- // instead, because the header does not exist in a blank session and the user would
1272
- // otherwise have no way back in.
1273
- if (supervisorOff) return null;
1273
+ // Hidden, or drawn by the overlay because it floats: the header renders nothing in
1274
+ // both cases. A floating figure inside the header's flow would push the header row
1275
+ // around as it moved, which is exactly the bug this split fixes.
1276
+ if (supervisorOff || floating) return null;
1274
1277
 
1275
1278
  const label = t('supervisor') + ' — ' + t(MODE_KEY[mode]);
1276
1279
  const size = appearance.size;
@@ -1341,6 +1344,22 @@ window.__ModuleLoader__.load({
1341
1344
  );
1342
1345
  }
1343
1346
 
1347
+ /**
1348
+ * The floating posture, rendered in the frame-wide overlay.
1349
+ *
1350
+ * `shell.overlay` is outside every column and scroll container, so an absolutely
1351
+ * positioned figure there cannot affect the header's layout. The component is shared
1352
+ * with the header seat; only the posture differs.
1353
+ */
1354
+ function FloatingSeat(props) {
1355
+ const t = useTranslate(props);
1356
+ const snapshot = useStore();
1357
+ useEffect(() => store.start(), []);
1358
+ if (snapshot.config === null) return null;
1359
+ if (snapshot.config.supervisor.show === false) return null;
1360
+ return h(SupervisorSeat, { t, forcePlace: 'float' });
1361
+ }
1362
+
1344
1363
  /* ------------------------------------------------------------ the panel */
1345
1364
 
1346
1365
  function StatValue(props) {
@@ -1979,6 +1998,15 @@ window.__ModuleLoader__.load({
1979
1998
  inject: () => ({}),
1980
1999
  }, PanelSeat));
1981
2000
 
2001
+ // The floating posture lives in the overlay so it cannot disturb the header row.
2002
+ ctx.slots.inject('shell.overlay', () => ctx.slots.register({
2003
+ name: 'shell.overlay',
2004
+ id: 'stall-guard-floating',
2005
+ order: 69,
2006
+ locale: NS,
2007
+ inject: () => ({}),
2008
+ }, FloatingSeat));
2009
+
1982
2010
  // The way back when the supervisor is hidden.
1983
2011
  ctx.slots.inject('shell.overlay', () => ctx.slots.register({
1984
2012
  name: 'shell.overlay',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-stall-guard",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "DSH 卡顿守卫:下载类命令(git clone / pnpm install / pip / curl)超时后自动中止,并把「换个下载源重试」的提示写进工具结果给智能体看,解决 GitHub 在国内网络不稳导致智能体一直干等的问题。另可按工具类型自定义超时秒数,并附一个只在卡顿时唤醒的 DeepSeek 监督员。",
5
5
  "keywords": [
6
6
  "dsh",