dsh-stall-guard 0.1.0 → 0.1.1
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 +17 -0
- package/README.md +7 -3
- package/client.js +51 -12
- package/lib/config.js +7 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,23 @@
|
|
|
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.1] - 2026-10-21
|
|
9
|
+
|
|
10
|
+
### 新增
|
|
11
|
+
|
|
12
|
+
- **气泡文字可关闭**:`supervisor.bubble`。关掉后图标仍会跳动提示有异常,但不显示文字。
|
|
13
|
+
旧配置文件没有这个键,默认显示气泡。
|
|
14
|
+
|
|
15
|
+
### 修复
|
|
16
|
+
|
|
17
|
+
- **点气泡打不开面板**:气泡原先在 `<button>` 内部且 `pointer-events:none`,
|
|
18
|
+
点击会穿透到背后的标题栏(表现为点出「下载 Session 日志」菜单)。
|
|
19
|
+
现在气泡是按钮的兄弟元素,有自己的点击与键盘激活。
|
|
20
|
+
- **气泡被挤成竖排**:宽度依赖内容,在窄的标题栏槽里被压成每行 3–4 字。
|
|
21
|
+
改为固定 200px(视口更窄时收窄),最多 4 行后截断。
|
|
22
|
+
- **过时提示文案**:`scenesHint` 仍写着「能自己决定要不要用模型写提示」,
|
|
23
|
+
但模型功能已删除。改为只描述超时。
|
|
24
|
+
|
|
8
25
|
## [0.1.0] - 2026-10-20
|
|
9
26
|
|
|
10
27
|
首个版本。核心用途:**下载卡住时自动掐掉,并把换源提示写给智能体看**。
|
package/README.md
CHANGED
|
@@ -128,8 +128,12 @@ $env:DSH_PROFILE # 桌面版一般是 desktop
|
|
|
128
128
|
|
|
129
129
|
### 显示开关
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
| 开关 | 作用 |
|
|
132
|
+
|---|---|
|
|
133
|
+
| 显示监督员 | 关掉后不再画形象,但**守卫照常工作**。右下角留一个半透明小点,点它开回面板 |
|
|
134
|
+
| 卡顿时显示文字气泡 | 关掉仍会**跳动**提示有异常,但不显示那句文字 |
|
|
135
|
+
|
|
136
|
+
点图标或点气泡都能打开面板。
|
|
133
137
|
|
|
134
138
|
### 图标外观(仅本浏览器)
|
|
135
139
|
|
|
@@ -258,7 +262,7 @@ $env:DSH_PROFILE # 桌面版一般是 desktop
|
|
|
258
262
|
## 开发
|
|
259
263
|
|
|
260
264
|
```bash
|
|
261
|
-
node --test test/*.test.mjs #
|
|
265
|
+
node --test test/*.test.mjs # 182 个用例
|
|
262
266
|
```
|
|
263
267
|
|
|
264
268
|
## 许可
|
package/client.js
CHANGED
|
@@ -189,7 +189,7 @@ window.__ModuleLoader__.load({
|
|
|
189
189
|
autoSwitch: 'Auto-switch fetch/search on timeout',
|
|
190
190
|
sectionPresets: 'Preset text (sent to the agent)',
|
|
191
191
|
sectionScenes: 'Each feature, configured separately',
|
|
192
|
-
scenesHint: 'Turn one off without affecting the others. Each has its own timeout
|
|
192
|
+
scenesHint: 'Turn one off without affecting the others. Each has its own timeout.',
|
|
193
193
|
sceneSeconds: 'Timeout (s)',
|
|
194
194
|
presetsHint: 'Write the exact text the agent reads when a stall is reported. Placeholders are filled in automatically; an empty box uses the built-in wording.',
|
|
195
195
|
presetSceneDownload: 'Download',
|
|
@@ -207,6 +207,8 @@ window.__ModuleLoader__.load({
|
|
|
207
207
|
sectionSupervisor: 'Supervisor',
|
|
208
208
|
showSupervisor: 'Show the supervisor',
|
|
209
209
|
showSupervisorHint: 'Off hides the figure but keeps the guard running; a small tab stays in the corner so you can switch it back.',
|
|
210
|
+
showBubble: 'Show the text bubble on a stall',
|
|
211
|
+
showBubbleHint: 'Off keeps the bouncing animation but hides the sentence. Click the figure or the bubble to open settings.',
|
|
210
212
|
supervisorHiddenHint: 'Supervisor hidden — click to open settings',
|
|
211
213
|
appearanceLabel: 'Icon appearance (this browser only)',
|
|
212
214
|
iconSize: 'Size',
|
|
@@ -279,7 +281,7 @@ window.__ModuleLoader__.load({
|
|
|
279
281
|
discardNo: '\u7ee7\u7eed\u7f16\u8f91',
|
|
280
282
|
sectionPresets: '\u9884\u8bbe\u6587\u5b57\uff08\u53d1\u7ed9\u667a\u80fd\u4f53\uff09',
|
|
281
283
|
sectionScenes: '\u6bcf\u4e2a\u529f\u80fd\u72ec\u7acb\u914d\u7f6e',
|
|
282
|
-
scenesHint: '\u5173\u6389\u4e00\u4e2a\u4e0d\u5f71\u54cd\u5176\u5b83\u3002\u6bcf\u4e2a\u7c7b\u578b\u6709\u81ea\u5df1\u7684\u8d85\u65f6\
|
|
284
|
+
scenesHint: '\u5173\u6389\u4e00\u4e2a\u4e0d\u5f71\u54cd\u5176\u5b83\u3002\u6bcf\u4e2a\u7c7b\u578b\u6709\u81ea\u5df1\u7684\u8d85\u65f6\u3002',
|
|
283
285
|
sceneSeconds: '\u8d85\u65f6\uff08\u79d2\uff09',
|
|
284
286
|
presetsHint: '\u76f4\u63a5\u5199\u4f60\u8981\u53d1\u7ed9\u667a\u80fd\u4f53\u7684\u6587\u5b57\uff0c\u5360\u4f4d\u7b26\u4f1a\u81ea\u52a8\u66ff\u6362\uff1b\u7a7a\u7740 = \u7528\u5185\u7f6e\u6587\u6848\u3002',
|
|
285
287
|
presetSceneDownload: '\u4e0b\u8f7d',
|
|
@@ -296,6 +298,8 @@ window.__ModuleLoader__.load({
|
|
|
296
298
|
downloadSeconds: '\u4e0b\u8f7d\u8d85\u65f6\uff08\u79d2\uff09',
|
|
297
299
|
showSupervisor: '\u663e\u793a\u76d1\u7763\u5458',
|
|
298
300
|
showSupervisorHint: '\u5173\u6389\u540e\u4e0d\u518d\u663e\u793a\u5f62\u8c61\uff0c\u4f46\u5b88\u536b\u4ecd\u5728\u8fd0\u884c\uff1b\u53f3\u4e0b\u89d2\u4f1a\u7559\u4e00\u4e2a\u5c0f\u70b9\uff0c\u70b9\u5b83\u53ef\u4ee5\u518d\u6253\u5f00\u3002',
|
|
301
|
+
showBubble: '\u5361\u987f\u65f6\u663e\u793a\u6587\u5b57\u6c14\u6ce1',
|
|
302
|
+
showBubbleHint: '\u5173\u6389\u4ecd\u4f1a\u8df3\u52a8\uff0c\u4f46\u4e0d\u663e\u793a\u6587\u5b57\u3002\u70b9\u56fe\u6807\u6216\u6c14\u6ce1\u90fd\u80fd\u6253\u5f00\u8bbe\u7f6e\u3002',
|
|
299
303
|
supervisorHiddenHint: '\u76d1\u7763\u5458\u5df2\u9690\u85cf \u2014 \u70b9\u51fb\u6253\u5f00\u8bbe\u7f6e',
|
|
300
304
|
appearanceLabel: '\u56fe\u6807\u5916\u89c2\uff08\u4ec5\u672c\u6d4f\u89c8\u5668\uff09',
|
|
301
305
|
iconSize: '\u5927\u5c0f',
|
|
@@ -496,6 +500,7 @@ window.__ModuleLoader__.load({
|
|
|
496
500
|
presets: normalizePresets(body.presets),
|
|
497
501
|
supervisor: {
|
|
498
502
|
show: sup.show !== false,
|
|
503
|
+
bubble: sup.bubble !== false,
|
|
499
504
|
display: pick(sup.display, DISPLAYS, 'avatar'),
|
|
500
505
|
},
|
|
501
506
|
};
|
|
@@ -858,6 +863,7 @@ window.__ModuleLoader__.load({
|
|
|
858
863
|
},
|
|
859
864
|
supervisor: {
|
|
860
865
|
show: source.supervisor.show !== false,
|
|
866
|
+
bubble: source.supervisor.bubble !== false,
|
|
861
867
|
display: source.supervisor.display,
|
|
862
868
|
},
|
|
863
869
|
};
|
|
@@ -905,6 +911,7 @@ window.__ModuleLoader__.load({
|
|
|
905
911
|
},
|
|
906
912
|
supervisor: {
|
|
907
913
|
show: draft.supervisor.show !== false,
|
|
914
|
+
bubble: draft.supervisor.bubble !== false,
|
|
908
915
|
display: pick(draft.supervisor.display, DISPLAYS, 'avatar'),
|
|
909
916
|
},
|
|
910
917
|
};
|
|
@@ -920,7 +927,7 @@ window.__ModuleLoader__.load({
|
|
|
920
927
|
*/
|
|
921
928
|
const CSS = [
|
|
922
929
|
/* ---- supervisor seat ---- */
|
|
923
|
-
'.dsg-seat{position:relative;display:inline-flex;flex:none;align-items:center;justify-content:center;pointer-events:auto}',
|
|
930
|
+
'.dsg-seat{position:relative;display:inline-flex;flex:none;align-items:center;justify-content:center;pointer-events:auto;overflow:visible}',
|
|
924
931
|
'.dsg-orb{box-sizing:border-box;display:inline-flex;position:relative;align-items:center;justify-content:center;margin:0;padding:0;border:none;background:transparent;font-family:inherit;cursor:pointer;overflow:visible;border-radius:var(--dsw-radius-sm,6px);pointer-events:auto}',
|
|
925
932
|
'.dsg-orb:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#4d6bfe);outline-offset:2px}',
|
|
926
933
|
'.dsg-orb[data-display="dot"]{width:22px;height:22px}',
|
|
@@ -937,11 +944,14 @@ window.__ModuleLoader__.load({
|
|
|
937
944
|
'.dsg-orb[data-mode="idle"] .dsg-avatar{opacity:.72;animation:none}',
|
|
938
945
|
'.dsg-orb[data-mode="watching"] .dsg-avatar{animation:dsg-sway 3.2s ease-in-out infinite}',
|
|
939
946
|
'.dsg-orb[data-mode="alert"] .dsg-avatar{animation:dsg-bounce-big .85s ease-in-out infinite}',
|
|
940
|
-
'.dsg-bubble{position:absolute;right:0;bottom:calc(100% + 7px);z-index:5;box-sizing:border-box;
|
|
947
|
+
'.dsg-bubble{position:absolute;right:0;bottom:calc(100% + 7px);z-index:5;box-sizing:border-box;width:200px;max-width:calc(100vw - 40px);padding:4px 8px;border:1px solid var(--dsw-alias-border-l1,var(--dsh-border,rgba(255,255,255,.12)));border-radius:var(--dsw-radius-sm,8px);background:var(--dsw-alias-bg-overlay,var(--dsh-surface,rgba(20,22,28,.96)));box-shadow:var(--dsw-elevation-soft,0 4px 18px rgba(0,0,0,.2));color:var(--dsw-alias-label-primary,var(--dsh-text-primary,#e6e6e6));font-size:11px;line-height:15px;text-align:left;white-space:normal;overflow-wrap:break-word;word-break:normal;max-height:120px;overflow:hidden;pointer-events:auto;cursor:pointer;animation:dsg-bubble-in .16s ease-out both}',
|
|
941
948
|
/* The header sits at the very top of the frame, so a bubble above the head
|
|
942
949
|
* would be clipped by the viewport; the seat measures once and flips it
|
|
943
950
|
* below when there is no room. */
|
|
944
951
|
'.dsg-bubble[data-place="below"]{bottom:auto;top:calc(100% + 7px)}',
|
|
952
|
+
'.dsg-bubble:hover{border-color:var(--dsw-alias-brand-primary,#4d6bfe)}',
|
|
953
|
+
/* Hidden state: the bubble is not rendered at all, so there is nothing to dim. */
|
|
954
|
+
|
|
945
955
|
/* ---- overlay panel ---- */
|
|
946
956
|
'.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}',
|
|
947
957
|
'.dsg-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap;flex:0 0 auto;padding-bottom:8px}',
|
|
@@ -1207,7 +1217,8 @@ window.__ModuleLoader__.load({
|
|
|
1207
1217
|
const mode = snapshot.state === null ? 'idle' : snapshot.state.supervisor.mode;
|
|
1208
1218
|
const display = config === null ? 'avatar' : config.supervisor.display;
|
|
1209
1219
|
const message = snapshot.state === null ? '' : snapshot.state.supervisor.message;
|
|
1210
|
-
const
|
|
1220
|
+
const bubbleOn = config === null ? true : config.supervisor.bubble !== false;
|
|
1221
|
+
const showBubble = !supervisorOff && bubbleOn && display === 'avatar' && mode === 'alert' && message !== '';
|
|
1211
1222
|
|
|
1212
1223
|
/* The seat can live in the top bar or float anywhere; a bubble above the head
|
|
1213
1224
|
* would be cut off by the viewport when it sits near the top, so measure once
|
|
@@ -1297,14 +1308,30 @@ window.__ModuleLoader__.load({
|
|
|
1297
1308
|
display === 'dot' ? h('span', { className: 'dsg-dot' }) : null,
|
|
1298
1309
|
display === 'icon' ? h(ShieldGlyph, { size: Math.round(size * 0.64) }) : null,
|
|
1299
1310
|
display === 'avatar' ? h(WhaleGlyph, { size: Math.round(size * 0.82), mode }) : null,
|
|
1300
|
-
showBubble
|
|
1301
|
-
? h('span', {
|
|
1302
|
-
className: 'dsg-bubble',
|
|
1303
|
-
'data-place': bubbleBelow ? 'below' : 'above',
|
|
1304
|
-
role: 'status',
|
|
1305
|
-
}, message)
|
|
1306
|
-
: null,
|
|
1307
1311
|
),
|
|
1312
|
+
/* The bubble is a SIBLING of the button, not a child: interactive content inside a
|
|
1313
|
+
* button is invalid and browsers route its clicks unpredictably, and content painted
|
|
1314
|
+
* outside the button box is not part of its hit area. */
|
|
1315
|
+
showBubble
|
|
1316
|
+
? h('span', {
|
|
1317
|
+
className: 'dsg-bubble',
|
|
1318
|
+
'data-place': bubbleBelow ? 'below' : 'above',
|
|
1319
|
+
role: 'button',
|
|
1320
|
+
tabIndex: 0,
|
|
1321
|
+
title: t('openPanel'),
|
|
1322
|
+
onClick: (event) => {
|
|
1323
|
+
event.stopPropagation();
|
|
1324
|
+
store.activate();
|
|
1325
|
+
},
|
|
1326
|
+
onKeyDown: (event) => {
|
|
1327
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
1328
|
+
event.preventDefault();
|
|
1329
|
+
event.stopPropagation();
|
|
1330
|
+
store.activate();
|
|
1331
|
+
}
|
|
1332
|
+
},
|
|
1333
|
+
}, message)
|
|
1334
|
+
: null,
|
|
1308
1335
|
);
|
|
1309
1336
|
}
|
|
1310
1337
|
|
|
@@ -1701,6 +1728,18 @@ window.__ModuleLoader__.load({
|
|
|
1701
1728
|
h('span', null, t('showSupervisor')),
|
|
1702
1729
|
),
|
|
1703
1730
|
h('p', { className: 'dsg-status' }, t('showSupervisorHint')),
|
|
1731
|
+
h('label', { className: 'dsg-check' },
|
|
1732
|
+
h('input', {
|
|
1733
|
+
type: 'checkbox',
|
|
1734
|
+
checked: draft.supervisor.bubble !== false,
|
|
1735
|
+
onChange: (event) => {
|
|
1736
|
+
const checked = event.target.checked;
|
|
1737
|
+
edit((next) => { next.supervisor = Object.assign({}, next.supervisor, { bubble: checked }); });
|
|
1738
|
+
},
|
|
1739
|
+
}),
|
|
1740
|
+
h('span', null, t('showBubble')),
|
|
1741
|
+
),
|
|
1742
|
+
h('p', { className: 'dsg-status' }, t('showBubbleHint')),
|
|
1704
1743
|
h('div', { className: 'dsg-label' }, t('displayLabel')),
|
|
1705
1744
|
h('div', { className: 'dsg-choices' },
|
|
1706
1745
|
DISPLAYS.map((value) => h('label', {
|
package/lib/config.js
CHANGED
|
@@ -48,6 +48,11 @@ export function defaults() {
|
|
|
48
48
|
supervisor: {
|
|
49
49
|
/** Whether the supervisor is drawn at all. Off still serves the API and the panel. */
|
|
50
50
|
show: true,
|
|
51
|
+
/**
|
|
52
|
+
* Whether the alert bubble shows its sentence. Off keeps the animation only, so a
|
|
53
|
+
* user who finds the text intrusive still sees that something is wrong.
|
|
54
|
+
*/
|
|
55
|
+
bubble: true,
|
|
51
56
|
display: DEFAULT_DISPLAY,
|
|
52
57
|
},
|
|
53
58
|
};
|
|
@@ -113,6 +118,7 @@ export function validateConfig(raw) {
|
|
|
113
118
|
const rawSupervisor = input.supervisor && typeof input.supervisor === 'object' ? input.supervisor : {};
|
|
114
119
|
|
|
115
120
|
const show = rawSupervisor.show === undefined ? base.supervisor.show : Boolean(rawSupervisor.show);
|
|
121
|
+
const bubble = rawSupervisor.bubble === undefined ? base.supervisor.bubble : Boolean(rawSupervisor.bubble);
|
|
116
122
|
|
|
117
123
|
let display = base.supervisor.display;
|
|
118
124
|
if (rawSupervisor.display !== undefined) {
|
|
@@ -142,6 +148,7 @@ export function validateConfig(raw) {
|
|
|
142
148
|
presets: presetResult.presets,
|
|
143
149
|
supervisor: {
|
|
144
150
|
show,
|
|
151
|
+
bubble,
|
|
145
152
|
display,
|
|
146
153
|
},
|
|
147
154
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-stall-guard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "DSH 卡顿守卫:下载类命令(git clone / pnpm install / pip / curl)超时后自动中止,并把「换个下载源重试」的提示写进工具结果给智能体看,解决 GitHub 在国内网络不稳导致智能体一直干等的问题。另可按工具类型自定义超时秒数,并附一个只在卡顿时唤醒的 DeepSeek 监督员。",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|