dsh-stall-guard 0.1.3 → 0.1.4

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 +34 -10
  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.4] - 2026-10-21
9
+
10
+ ### 修复
11
+
12
+ - **切到「浮动」后图标消失**:0.1.3 把浮动态拆到 overlay 渲染时,标题栏座位的守卫
13
+ `if (supervisorOff || floating) return null` 同时也把 overlay 座位挡掉了 ——
14
+ 因为 overlay 座位收到的 `floating` 恒为 true。结果是图标彻底不画。
15
+ 现在区分「这个座位要画的形态(forcedFloat)」与「用户选择的形态(wantsFloat)」:
16
+ 标题栏在 `wantsFloat && !forcedFloat` 时让位,overlay 座位永不让位。
17
+ - **两个座位可能同时画图标**:overlay 座位现在只在 `place === 'float'` 时渲染。
18
+ - 外观状态改为共享 `useAppearance()` 钩子(`useSyncExternalStore`),
19
+ 三个消费点(标题栏、浮动态、面板)对同一份记录同步重绘,
20
+ 修掉面板改尺寸时图标不实时变化的问题。
21
+
8
22
  ## [0.1.3] - 2026-10-21
9
23
 
10
24
  ### 修复
package/client.js CHANGED
@@ -1188,6 +1188,19 @@ window.__ModuleLoader__.load({
1188
1188
  }
1189
1189
  }
1190
1190
 
1191
+ /**
1192
+ * Subscribe to the appearance record.
1193
+ *
1194
+ * The record lives outside the polled snapshot, so it needs its own subscription. A
1195
+ * shared hook keeps every consumer honest: an appearance change re-renders all of them.
1196
+ */
1197
+ function useAppearance() {
1198
+ return useSyncExternalStore(
1199
+ (listener) => store.subscribeAppearance(listener),
1200
+ () => store.getAppearance(),
1201
+ );
1202
+ }
1203
+
1191
1204
  function useTranslate(props) {
1192
1205
  return props.t !== undefined && typeof props.t === 'function' ? props.t : (boundT || ((key) => key));
1193
1206
  }
@@ -1208,11 +1221,10 @@ window.__ModuleLoader__.load({
1208
1221
  const snapshot = useStore();
1209
1222
  const orbRef = useRef(null);
1210
1223
  const [bubbleBelow, setBubbleBelow] = useState(false);
1211
- const [appearance, setAppearance] = useState(readAppearance);
1224
+ const appearance = useAppearance();
1212
1225
  const [dragging, setDragging] = useState(false);
1213
1226
 
1214
1227
  useEffect(() => store.start(), []);
1215
- useEffect(() => store.subscribeAppearance(setAppearance), []);
1216
1228
 
1217
1229
  const config = snapshot.config;
1218
1230
  const supervisorOff = config !== null && config.supervisor.show === false;
@@ -1238,8 +1250,16 @@ window.__ModuleLoader__.load({
1238
1250
 
1239
1251
  /* Float placement: drag moves the control, and the position is clamped into the
1240
1252
  * viewport on release so a window resize cannot strand it off-screen. */
1241
- // The overlay seat forces the floating posture; the header seat reads the setting.
1242
- const floating = props.forcePlace === 'float' || appearance.place === 'float';
1253
+ /**
1254
+ * Which posture this render draws.
1255
+ *
1256
+ * The overlay seat forces floating; the header seat reads the user's setting. The two
1257
+ * must be distinguished, because the header seat has to bail out when the chosen
1258
+ * posture is floating — while the overlay seat must not bail out for the same reason.
1259
+ */
1260
+ const forcedFloat = props.forcePlace === 'float';
1261
+ const wantsFloat = appearance.place === 'float';
1262
+ const floating = forcedFloat || wantsFloat;
1243
1263
  const startDrag = useCallback((event) => {
1244
1264
  if (!floating) return;
1245
1265
  if (event.button !== undefined && event.button !== 0) return;
@@ -1270,10 +1290,11 @@ window.__ModuleLoader__.load({
1270
1290
  event.preventDefault();
1271
1291
  }, [floating]);
1272
1292
 
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;
1293
+ // The header seat renders nothing when the figure is hidden OR when the overlay owns
1294
+ // it — a floating figure inside the header's flow would push that row around as it
1295
+ // moved. The overlay seat asked for this render, so it never bails out here.
1296
+ if (supervisorOff) return null;
1297
+ if (wantsFloat && !forcedFloat) return null;
1277
1298
 
1278
1299
  const label = t('supervisor') + ' — ' + t(MODE_KEY[mode]);
1279
1300
  const size = appearance.size;
@@ -1354,9 +1375,13 @@ window.__ModuleLoader__.load({
1354
1375
  function FloatingSeat(props) {
1355
1376
  const t = useTranslate(props);
1356
1377
  const snapshot = useStore();
1378
+ /* The overlay draws the figure only in the floating posture. Without this check both
1379
+ * seats would render it, and the header would show a second copy. */
1380
+ const appearance = useAppearance();
1357
1381
  useEffect(() => store.start(), []);
1358
1382
  if (snapshot.config === null) return null;
1359
1383
  if (snapshot.config.supervisor.show === false) return null;
1384
+ if (appearance.place !== 'float') return null;
1360
1385
  return h(SupervisorSeat, { t, forcePlace: 'float' });
1361
1386
  }
1362
1387
 
@@ -1401,8 +1426,7 @@ window.__ModuleLoader__.load({
1401
1426
  const presetLocale = hostLocale() === 'en' ? 'en' : 'zh';
1402
1427
  /* Appearance is browser-local, so the panel mirrors it separately from the
1403
1428
  * Host draft; saving the config must not overwrite it and vice versa. */
1404
- const [localAppearance, setLocalAppearance] = useState(() => store.getAppearance());
1405
- useEffect(() => store.subscribeAppearance(setLocalAppearance), []);
1429
+ const localAppearance = useAppearance();
1406
1430
  const [dirty, setDirty] = useState(false);
1407
1431
  const [status, setStatus] = useState({ kind: 'idle', text: '' });
1408
1432
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-stall-guard",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "DSH 卡顿守卫:下载类命令(git clone / pnpm install / pip / curl)超时后自动中止,并把「换个下载源重试」的提示写进工具结果给智能体看,解决 GitHub 在国内网络不稳导致智能体一直干等的问题。另可按工具类型自定义超时秒数,并附一个只在卡顿时唤醒的 DeepSeek 监督员。",
5
5
  "keywords": [
6
6
  "dsh",