dsh-stall-guard 0.1.2 → 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.
- package/CHANGELOG.md +28 -0
- package/client.js +63 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@
|
|
|
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
|
+
|
|
22
|
+
## [0.1.3] - 2026-10-21
|
|
23
|
+
|
|
24
|
+
### 修复
|
|
25
|
+
|
|
26
|
+
- **拖动图标会带动上方状态栏**:浮动态原先仍渲染在标题栏槽位里,那个槽位是正常文档流
|
|
27
|
+
中的 flex 项,`position:fixed` 在那里无效,图标移动时会把整行撑动。
|
|
28
|
+
现在浮动态改由 `shell.overlay` 渲染(真正脱离所有列与滚动容器),标题栏在浮动时
|
|
29
|
+
渲染空。这样图标可以像贴纸一样拖到任意位置,不影响任何其他元素。
|
|
30
|
+
- **调整大小时看不到实时预览**:设置面板原先从 `top:56px` 开始展开,正好压住标题栏
|
|
31
|
+
上的图标,所以拖滑块时看不到尺寸变化。面板改为从标题栏下方开始(`top:118px`)。
|
|
32
|
+
- 浮动态的层级提到面板之上(`z-index:75`),即使图标被拖到面板范围内也仍然可见可拖。
|
|
33
|
+
- 拖动位置改从 store 读取而不是每帧读 localStorage,避免高频拖动时状态竞争、
|
|
34
|
+
丢中间位置。
|
|
35
|
+
|
|
8
36
|
## [0.1.2] - 2026-10-21
|
|
9
37
|
|
|
10
38
|
### 修复
|
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:
|
|
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))}',
|
|
@@ -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
|
|
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,7 +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
|
-
|
|
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;
|
|
1242
1263
|
const startDrag = useCallback((event) => {
|
|
1243
1264
|
if (!floating) return;
|
|
1244
1265
|
if (event.button !== undefined && event.button !== 0) return;
|
|
@@ -1254,7 +1275,9 @@ window.__ModuleLoader__.load({
|
|
|
1254
1275
|
setDragging(true);
|
|
1255
1276
|
const nextX = Math.max(0, Math.min(window.innerWidth - rect.width, moveEvent.clientX - offsetX));
|
|
1256
1277
|
const nextY = Math.max(0, Math.min(window.innerHeight - rect.height, moveEvent.clientY - offsetY));
|
|
1257
|
-
|
|
1278
|
+
// Read from the store, not localStorage: a per-frame disk read would race with
|
|
1279
|
+
// the in-memory value and drop intermediate positions.
|
|
1280
|
+
store.setAppearance({ ...store.getAppearance(), x: Math.round(nextX), y: Math.round(nextY) });
|
|
1258
1281
|
};
|
|
1259
1282
|
const onUp = () => {
|
|
1260
1283
|
window.removeEventListener('pointermove', onMove);
|
|
@@ -1267,10 +1290,11 @@ window.__ModuleLoader__.load({
|
|
|
1267
1290
|
event.preventDefault();
|
|
1268
1291
|
}, [floating]);
|
|
1269
1292
|
|
|
1270
|
-
//
|
|
1271
|
-
//
|
|
1272
|
-
//
|
|
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.
|
|
1273
1296
|
if (supervisorOff) return null;
|
|
1297
|
+
if (wantsFloat && !forcedFloat) return null;
|
|
1274
1298
|
|
|
1275
1299
|
const label = t('supervisor') + ' — ' + t(MODE_KEY[mode]);
|
|
1276
1300
|
const size = appearance.size;
|
|
@@ -1341,6 +1365,26 @@ window.__ModuleLoader__.load({
|
|
|
1341
1365
|
);
|
|
1342
1366
|
}
|
|
1343
1367
|
|
|
1368
|
+
/**
|
|
1369
|
+
* The floating posture, rendered in the frame-wide overlay.
|
|
1370
|
+
*
|
|
1371
|
+
* `shell.overlay` is outside every column and scroll container, so an absolutely
|
|
1372
|
+
* positioned figure there cannot affect the header's layout. The component is shared
|
|
1373
|
+
* with the header seat; only the posture differs.
|
|
1374
|
+
*/
|
|
1375
|
+
function FloatingSeat(props) {
|
|
1376
|
+
const t = useTranslate(props);
|
|
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();
|
|
1381
|
+
useEffect(() => store.start(), []);
|
|
1382
|
+
if (snapshot.config === null) return null;
|
|
1383
|
+
if (snapshot.config.supervisor.show === false) return null;
|
|
1384
|
+
if (appearance.place !== 'float') return null;
|
|
1385
|
+
return h(SupervisorSeat, { t, forcePlace: 'float' });
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1344
1388
|
/* ------------------------------------------------------------ the panel */
|
|
1345
1389
|
|
|
1346
1390
|
function StatValue(props) {
|
|
@@ -1382,8 +1426,7 @@ window.__ModuleLoader__.load({
|
|
|
1382
1426
|
const presetLocale = hostLocale() === 'en' ? 'en' : 'zh';
|
|
1383
1427
|
/* Appearance is browser-local, so the panel mirrors it separately from the
|
|
1384
1428
|
* Host draft; saving the config must not overwrite it and vice versa. */
|
|
1385
|
-
const
|
|
1386
|
-
useEffect(() => store.subscribeAppearance(setLocalAppearance), []);
|
|
1429
|
+
const localAppearance = useAppearance();
|
|
1387
1430
|
const [dirty, setDirty] = useState(false);
|
|
1388
1431
|
const [status, setStatus] = useState({ kind: 'idle', text: '' });
|
|
1389
1432
|
|
|
@@ -1979,6 +2022,15 @@ window.__ModuleLoader__.load({
|
|
|
1979
2022
|
inject: () => ({}),
|
|
1980
2023
|
}, PanelSeat));
|
|
1981
2024
|
|
|
2025
|
+
// The floating posture lives in the overlay so it cannot disturb the header row.
|
|
2026
|
+
ctx.slots.inject('shell.overlay', () => ctx.slots.register({
|
|
2027
|
+
name: 'shell.overlay',
|
|
2028
|
+
id: 'stall-guard-floating',
|
|
2029
|
+
order: 69,
|
|
2030
|
+
locale: NS,
|
|
2031
|
+
inject: () => ({}),
|
|
2032
|
+
}, FloatingSeat));
|
|
2033
|
+
|
|
1982
2034
|
// The way back when the supervisor is hidden.
|
|
1983
2035
|
ctx.slots.inject('shell.overlay', () => ctx.slots.register({
|
|
1984
2036
|
name: 'shell.overlay',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-stall-guard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "DSH 卡顿守卫:下载类命令(git clone / pnpm install / pip / curl)超时后自动中止,并把「换个下载源重试」的提示写进工具结果给智能体看,解决 GitHub 在国内网络不稳导致智能体一直干等的问题。另可按工具类型自定义超时秒数,并附一个只在卡顿时唤醒的 DeepSeek 监督员。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|