@morehao/dsh-skills-console 0.5.1 → 0.5.2
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/README.md +1 -1
- package/client.js +152 -179
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ plugin_manager install_bundle(target = <本仓库绝对路径>)
|
|
|
90
90
|
1. **添加技能**:点右上角「添加技能」,填 `owner/repo` 或 GitHub URL,点「检测技能」;仓库里有多个技能时勾选要装的(支持多选,默认全选,列表带每个技能的说明),只有一个会默认勾上。检测不到时可以手填技能名,留空则装仓库内全部。
|
|
91
91
|
2. **共享至其他 Agent**:只有「只读自己目录」的 Agent 才需要这一步(例如 Claude Code)。点行内「共享设置」勾选目标 Agent;本来就读共享目录的 Agent 不在列表里。之后新装技能默认共享至哪些 Agent,用页头「新安装时自动共享」设定(默认一个都不勾)。
|
|
92
92
|
3. **检查更新**:点列表头上的刷新图标;有更新的行会亮起「更新」,也可以一次「全部更新」。本地改过的技能会先要求确认。
|
|
93
|
-
4. **调用策略**:点行内「自动 / 仅手动 /
|
|
93
|
+
4. **调用策略**:点行内「自动 / 仅手动 / 完全停用」状态按钮,在居中的调用策略弹窗里切换。自动=模型与 `/` 都能调用;仅手动=只改 `SKILL.md` 的 `disable-model-invocation`,`/` 仍可用;完全停用=把 `SKILL.md` 改名为 `SKILL.md.disabled` 并留 marker,恢复时回到停用前的模式。作者已在 `SKILL.md` 里声明仅手动时,chip 只读展示,不会被覆盖。停用期间更新 / 安装会被拒绝,避免文件被悄悄写回。
|
|
94
94
|
|
|
95
95
|
## 安全与可靠性
|
|
96
96
|
|
package/client.js
CHANGED
|
@@ -1134,6 +1134,19 @@ var CSS = `
|
|
|
1134
1134
|
.dshsc-pop-label em { font-style: normal; font-size: 11px; color: var(--dsw-alias-label-tertiary); }
|
|
1135
1135
|
.dshsc-pop-name { display: inline-flex; align-items: baseline; gap: 6px; }
|
|
1136
1136
|
.dshsc-pop-hint { font-size: 11px; line-height: 1.5; color: var(--dsw-alias-label-tertiary); }
|
|
1137
|
+
/* 与 DSH 自带开关同尺寸/同 token:关是 border-l3 轨道,开是 brand-primary 轨道。
|
|
1138
|
+
0.5.0 换三档 chip 时这组规则被一起删掉,但「侧边栏入口」还在用 .dshsc-switch,补回来。 */
|
|
1139
|
+
.dshsc-switch { box-sizing: border-box; position: relative; flex: none; width: 36px; height: 20px; padding: 2px;
|
|
1140
|
+
border: 0; border-radius: 999px; background: var(--dsw-alias-border-l3); cursor: pointer;
|
|
1141
|
+
transition: background .14s ease; }
|
|
1142
|
+
.dshsc-switch:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 2px; }
|
|
1143
|
+
.dshsc-switch:disabled { cursor: not-allowed; opacity: .5; }
|
|
1144
|
+
.dshsc-switch[aria-checked="true"] { background: var(--dsw-alias-brand-primary); }
|
|
1145
|
+
.dshsc-knob { display: block; width: 16px; height: 16px; border-radius: 50%;
|
|
1146
|
+
background: var(--dsw-alias-switch-thumb, #fff); box-shadow: 0 1px 2px rgba(0, 0, 0, .28);
|
|
1147
|
+
transition: transform .12s ease, background .12s ease; }
|
|
1148
|
+
.dshsc-switch[aria-checked="true"] .dshsc-knob { transform: translateX(16px);
|
|
1149
|
+
background: var(--dsw-alias-label-primary-foreground, #fff); }
|
|
1137
1150
|
|
|
1138
1151
|
.dshsc-btn { font: inherit; font-size: 12px; line-height: 1; padding: 7px 11px; border-radius: 8px; cursor: pointer;
|
|
1139
1152
|
white-space: nowrap;
|
|
@@ -1357,10 +1370,15 @@ var CSS = `
|
|
|
1357
1370
|
.dshsc-sub-list { display: flex; flex-direction: column; padding: 0 12px 7px 46px;
|
|
1358
1371
|
background: color-mix(in srgb, var(--dsw-alias-bg-layer-2) 22%, transparent);
|
|
1359
1372
|
border-top: 1px solid var(--dsw-alias-border-l1); }
|
|
1373
|
+
/* 条目操作列 92px 是照两枚按钮预留的,眼下每行只有一枚「安装」(两字 ≈ 43px:0 9px padding + 边框)。
|
|
1374
|
+
表头「操作」和已装行的破折号都按按钮宽度做一个右对齐的居中盒子:三者落在同一条中轴上,
|
|
1375
|
+
既不贴着列右缘,也不用改列宽 / 挪按钮。换语言或字号时盒子只是不再严格等于按钮宽度。 */
|
|
1376
|
+
.dshsc-sub-list { --dshsc-entry-act: 44px; }
|
|
1360
1377
|
.dshsc-entryhead { display: grid; grid-template-columns: minmax(0, 1fr) 110px 92px; gap: 10px;
|
|
1361
1378
|
align-items: center; height: 26px; border-bottom: 1px solid var(--dsw-alias-border-l1);
|
|
1362
1379
|
color: var(--dsw-alias-label-tertiary); font-size: 10px; font-weight: 500; letter-spacing: .02em; }
|
|
1363
|
-
.dshsc-entryhead .right {
|
|
1380
|
+
.dshsc-entryhead .right { justify-self: end; box-sizing: border-box; width: var(--dshsc-entry-act);
|
|
1381
|
+
text-align: center; padding-right: 0; }
|
|
1364
1382
|
.dshsc-sub-entry { display: grid; grid-template-columns: minmax(0, 1fr) 110px 92px; gap: 10px;
|
|
1365
1383
|
align-items: center; font-size: 12px; padding: 6px 0; border-top: 1px solid var(--dsw-alias-border-l1); }
|
|
1366
1384
|
.dshsc-entryhead + .dshsc-sub-entry { border-top: 0; }
|
|
@@ -1374,8 +1392,9 @@ var CSS = `
|
|
|
1374
1392
|
.dshsc-state.ok svg { color: var(--dsw-alias-state-success-primary); }
|
|
1375
1393
|
.dshsc-sub-entry .dshsc-actions { justify-self: end; display: flex; justify-content: flex-end; }
|
|
1376
1394
|
.dshsc-sub-entry .dshsc-btn { height: 24px; padding: 0 9px; font-size: 11.5px; }
|
|
1377
|
-
/*
|
|
1378
|
-
.dshsc-sub-entry .dshsc-noop {
|
|
1395
|
+
/* 已装条目的操作列没有动作:破折号占位,居中在按钮宽度里,和表头、安装按钮同一条中轴 */
|
|
1396
|
+
.dshsc-sub-entry .dshsc-noop { box-sizing: border-box; width: var(--dshsc-entry-act); padding: 0;
|
|
1397
|
+
text-align: center; color: var(--dsw-alias-label-tertiary); font-size: 11.5px; line-height: 24px; }
|
|
1379
1398
|
/* 设置页的真实宽度常常远小于窗口(侧栏 + 页面缩放),视口 media query 不可靠;
|
|
1380
1399
|
以 .dshsc-root 自身宽度为准,窄面板时切两列,避免固定列把 Agent 标签挤成竖排。
|
|
1381
1400
|
断点取 860 而不是贴着面板常见的 ~900:四列网格需要 280 + 150 + 操作列 + 3×14 gap + 中间列,
|
|
@@ -1404,7 +1423,7 @@ var CSS = `
|
|
|
1404
1423
|
}
|
|
1405
1424
|
.dshsc-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; }
|
|
1406
1425
|
|
|
1407
|
-
/* 调用策略 chip
|
|
1426
|
+
/* 调用策略 chip:一个入口显示当前模式;点开三档弹窗。窄列里允许省略,不撑破 102px */
|
|
1408
1427
|
.dshsc-chip { box-sizing: border-box; display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
|
|
1409
1428
|
height: 24px; padding: 0 9px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 999px;
|
|
1410
1429
|
background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-secondary); font-family: inherit;
|
|
@@ -1428,40 +1447,40 @@ var CSS = `
|
|
|
1428
1447
|
.dshsc-chip.legacy { color: var(--dsw-alias-label-tertiary); background: var(--dsw-alias-bg-layer-2); }
|
|
1429
1448
|
.dshsc-chip.muted { color: var(--dsw-alias-label-tertiary); cursor: default; opacity: .8; }
|
|
1430
1449
|
|
|
1431
|
-
|
|
1432
|
-
|
|
1450
|
+
/* 锚定浮层外壳:介绍浮层等共用(fixed + portal 到宿主弹窗),不再和调用策略弹窗共用 */
|
|
1451
|
+
.dshsc-floatpop { position: fixed; z-index: 70; box-sizing: border-box; width: min(380px, calc(100vw - 16px));
|
|
1452
|
+
max-height: min(600px, calc(100vh - 16px)); overflow: hidden; padding: 14px;
|
|
1433
1453
|
background: var(--dsw-alias-bg-base); border: 1px solid var(--dsw-alias-border-l1); border-radius: 14px;
|
|
1434
1454
|
box-shadow: 0 18px 48px rgba(0,0,0,.32), 0 2px 8px rgba(0,0,0,.16);
|
|
1435
1455
|
display: flex; flex-direction: column; gap: 10px; }
|
|
1436
|
-
.dshsc-
|
|
1437
|
-
.dshsc-
|
|
1438
|
-
.dshsc-
|
|
1439
|
-
.dshsc-
|
|
1456
|
+
.dshsc-floatpop-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; flex: none; }
|
|
1457
|
+
.dshsc-floatpop-title { font-size: 13px; font-weight: 600; color: var(--dsw-alias-label-primary); }
|
|
1458
|
+
.dshsc-floatpop-sub { margin: 2px 0 0; font-size: 11px; line-height: 16px; color: var(--dsw-alias-label-tertiary); }
|
|
1459
|
+
.dshsc-floatpop-close { flex: none; width: 24px; height: 24px; margin: -4px -4px 0 0; border: 0; border-radius: 6px;
|
|
1440
1460
|
background: transparent; color: var(--dsw-alias-label-secondary); font-size: 18px; line-height: 1; cursor: pointer; }
|
|
1441
|
-
.dshsc-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1461
|
+
.dshsc-floatpop-close:hover { background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-primary); }
|
|
1462
|
+
|
|
1463
|
+
/* 调用策略:标准居中弹窗(Overlay)里的单选列表;行距 / 圆点尺寸对齐共享设置的 .dshsc-check */
|
|
1464
|
+
.dshsc-policy-options { max-height: none; overflow: visible; }
|
|
1465
|
+
.dshsc-policyopt { box-sizing: border-box; display: flex; align-items: flex-start; gap: 9px; width: 100%;
|
|
1466
|
+
padding: 5px 8px; text-align: left; border: 0; border-radius: 8px;
|
|
1467
|
+
background: transparent; color: var(--dsw-alias-label-primary); font-family: inherit; cursor: pointer; }
|
|
1468
|
+
.dshsc-policyopt:hover:not(:disabled) { background: var(--dsw-alias-bg-layer-2); }
|
|
1469
|
+
.dshsc-policyopt:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: -2px; }
|
|
1449
1470
|
.dshsc-policyopt:disabled { cursor: not-allowed; opacity: .55; }
|
|
1450
1471
|
.dshsc-policyopt.static { cursor: default; }
|
|
1451
|
-
.dshsc-policyopt
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1472
|
+
.dshsc-policyopt.static:hover { background: transparent; }
|
|
1473
|
+
.dshsc-policyopt-dot { box-sizing: border-box; flex: none; width: 15px; height: 15px; margin-top: 2px;
|
|
1474
|
+
border-radius: 50%; border: 1px solid var(--dsw-alias-border-l2); background: var(--dsw-alias-bg-layer-1); }
|
|
1475
|
+
.dshsc-policyopt.active .dshsc-policyopt-dot { border: 5px solid var(--dsw-alias-brand-primary); }
|
|
1455
1476
|
.dshsc-policyopt-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
1456
|
-
.dshsc-policyopt-body b { font-size:
|
|
1477
|
+
.dshsc-policyopt-body b { font-size: 13px; font-weight: 600; }
|
|
1457
1478
|
.dshsc-policyopt-body small { font-size: 11px; line-height: 15px; color: var(--dsw-alias-label-tertiary); }
|
|
1458
1479
|
.dshsc-policy-note { padding: 7px 9px; border-radius: 8px; background: var(--dsw-alias-bg-layer-2);
|
|
1459
1480
|
color: var(--dsw-alias-label-secondary); font-size: 11px; line-height: 15px; }
|
|
1460
1481
|
.dshsc-policy-note.warn, .dshsc-policy-note.author { color: var(--dsw-alias-state-warn-primary);
|
|
1461
1482
|
background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 9%, transparent); }
|
|
1462
1483
|
.dshsc-policy-hidden { display: flex; flex-direction: column; gap: 8px; }
|
|
1463
|
-
.dshsc-policy-restore { align-self: flex-start; }
|
|
1464
|
-
.dshsc-policy-foot { display: flex; justify-content: flex-end; gap: 6px; }
|
|
1465
1484
|
.dshsc-policy-confirm { display: flex; flex-direction: column; gap: 6px; padding: 10px; border-radius: 9px;
|
|
1466
1485
|
border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 34%, var(--dsw-alias-border-l1));
|
|
1467
1486
|
background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 7%, transparent); }
|
|
@@ -1657,7 +1676,7 @@ var CSS = `
|
|
|
1657
1676
|
.dshsc-intro-btn:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 2px; }
|
|
1658
1677
|
.dshsc-intro-btn .dshsc-spark { font-size: 10px; color: var(--dsw-alias-brand-primary); }
|
|
1659
1678
|
|
|
1660
|
-
/*
|
|
1679
|
+
/* 介绍浮层:复用通用 floatpop 外壳(fixed + portal),只调内容排版 */
|
|
1661
1680
|
.dshsc-intro-pop { width: min(360px, calc(100vw - 16px)); gap: 7px; }
|
|
1662
1681
|
.dshsc-intro-text { margin: 0; font-size: 12.5px; line-height: 1.7; color: var(--dsw-alias-label-primary);
|
|
1663
1682
|
white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
@@ -2558,23 +2577,23 @@ function IntroPopover({
|
|
|
2558
2577
|
"div",
|
|
2559
2578
|
{
|
|
2560
2579
|
ref,
|
|
2561
|
-
className: "dshsc-
|
|
2580
|
+
className: "dshsc-floatpop dshsc-intro-pop",
|
|
2562
2581
|
role: "dialog",
|
|
2563
2582
|
"aria-label": `${t("intro.title")} · ${name}`,
|
|
2564
2583
|
style: { left: `${pos.left}px`, top: `${pos.top}px`, visibility: pos.visibility }
|
|
2565
2584
|
},
|
|
2566
2585
|
h(
|
|
2567
2586
|
"div",
|
|
2568
|
-
{ className: "dshsc-
|
|
2587
|
+
{ className: "dshsc-floatpop-head" },
|
|
2569
2588
|
h(
|
|
2570
2589
|
"div",
|
|
2571
2590
|
null,
|
|
2572
|
-
h("div", { className: "dshsc-
|
|
2573
|
-
h("div", { className: "dshsc-
|
|
2591
|
+
h("div", { className: "dshsc-floatpop-title" }, `✨ ${t("intro.title")}`),
|
|
2592
|
+
h("div", { className: "dshsc-floatpop-sub", title: subtitle || name }, subtitle || name)
|
|
2574
2593
|
),
|
|
2575
2594
|
h("button", {
|
|
2576
2595
|
type: "button",
|
|
2577
|
-
className: "dshsc-
|
|
2596
|
+
className: "dshsc-floatpop-close",
|
|
2578
2597
|
"aria-label": t("action.close"),
|
|
2579
2598
|
onClick: onClose
|
|
2580
2599
|
}, "×")
|
|
@@ -2589,40 +2608,40 @@ function IntroPopover({
|
|
|
2589
2608
|
));
|
|
2590
2609
|
}
|
|
2591
2610
|
|
|
2592
|
-
// client/views/policy-
|
|
2611
|
+
// client/views/policy-modal.js
|
|
2593
2612
|
var import_react4 = __toESM(require("react"), 1);
|
|
2594
|
-
|
|
2613
|
+
|
|
2614
|
+
// client/views/overlay.js
|
|
2615
|
+
function Overlay({ t, title, children, footer, onCancel }) {
|
|
2616
|
+
useOverlayLayer(true, onCancel);
|
|
2617
|
+
return portalize(h(
|
|
2618
|
+
"div",
|
|
2619
|
+
{ className: "dshsc-overlay", onClick: (event) => {
|
|
2620
|
+
if (event.target === event.currentTarget) onCancel?.();
|
|
2621
|
+
} },
|
|
2622
|
+
h(
|
|
2623
|
+
"div",
|
|
2624
|
+
{ className: "dshsc-modal", role: "dialog", "aria-modal": "true" },
|
|
2625
|
+
h("button", {
|
|
2626
|
+
className: "dshsc-modal-close",
|
|
2627
|
+
"aria-label": t("action.cancel"),
|
|
2628
|
+
onClick: (event) => {
|
|
2629
|
+
event.stopPropagation();
|
|
2630
|
+
onCancel?.();
|
|
2631
|
+
}
|
|
2632
|
+
}, "×"),
|
|
2633
|
+
h("h3", null, title),
|
|
2634
|
+
children,
|
|
2635
|
+
h("div", { className: "dshsc-modal-foot" }, footer)
|
|
2636
|
+
)
|
|
2637
|
+
), overlayHost());
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
// client/views/policy-modal.js
|
|
2641
|
+
function PolicyModal({ t, row, busy, onClose, onSave, onUnpark }) {
|
|
2595
2642
|
const initial = row.mode === "hidden" ? "auto" : row.mode;
|
|
2596
2643
|
const [mode, setMode] = import_react4.default.useState(initial);
|
|
2597
2644
|
const [confirming, setConfirming] = import_react4.default.useState(false);
|
|
2598
|
-
const ref = import_react4.default.useRef(null);
|
|
2599
|
-
const [pos, setPos] = import_react4.default.useState({ left: 0, top: 0, visibility: "hidden" });
|
|
2600
|
-
useOverlayLayer(true, onClose);
|
|
2601
|
-
import_react4.default.useLayoutEffect(() => {
|
|
2602
|
-
const node = ref.current;
|
|
2603
|
-
if (!node || !anchor || typeof window === "undefined") return;
|
|
2604
|
-
const rect = node.getBoundingClientRect();
|
|
2605
|
-
const width = rect.width || 360;
|
|
2606
|
-
const height = rect.height || 320;
|
|
2607
|
-
let left = anchor.left + anchor.width / 2 - width / 2;
|
|
2608
|
-
left = Math.max(8, Math.min(left, window.innerWidth - width - 8));
|
|
2609
|
-
let top = anchor.bottom + 8;
|
|
2610
|
-
if (top + height > window.innerHeight - 8) {
|
|
2611
|
-
top = Math.max(8, anchor.top - height - 8);
|
|
2612
|
-
}
|
|
2613
|
-
setPos({ left, top, visibility: "visible" });
|
|
2614
|
-
}, [anchor, confirming, mode]);
|
|
2615
|
-
import_react4.default.useEffect(() => {
|
|
2616
|
-
if (typeof document === "undefined") return void 0;
|
|
2617
|
-
const onPointerDown = (event) => {
|
|
2618
|
-
const target = event?.target;
|
|
2619
|
-
if (ref.current?.contains?.(target)) return;
|
|
2620
|
-
if (anchorEl?.contains?.(target)) return;
|
|
2621
|
-
onClose();
|
|
2622
|
-
};
|
|
2623
|
-
document.addEventListener("pointerdown", onPointerDown, true);
|
|
2624
|
-
return () => document.removeEventListener("pointerdown", onPointerDown, true);
|
|
2625
|
-
}, [anchorEl, onClose]);
|
|
2626
2645
|
const hidden = row.mode === "hidden";
|
|
2627
2646
|
const author = row.origin === "author" && row.mode === "manual";
|
|
2628
2647
|
const flat = row.kind === "file";
|
|
@@ -2644,7 +2663,8 @@ function PolicyPopover({ t, row, anchor, anchorEl, busy, onClose, onSave, onUnpa
|
|
|
2644
2663
|
type: "button",
|
|
2645
2664
|
key: `policy-${id}`,
|
|
2646
2665
|
className: `dshsc-policyopt${mode === id ? " active" : ""}`,
|
|
2647
|
-
"
|
|
2666
|
+
role: "radio",
|
|
2667
|
+
"aria-checked": String(mode === id),
|
|
2648
2668
|
disabled: busy || flat,
|
|
2649
2669
|
onClick: () => choose(id)
|
|
2650
2670
|
},
|
|
@@ -2656,95 +2676,85 @@ function PolicyPopover({ t, row, anchor, anchorEl, busy, onClose, onSave, onUnpa
|
|
|
2656
2676
|
h("small", null, desc)
|
|
2657
2677
|
)
|
|
2658
2678
|
);
|
|
2659
|
-
|
|
2660
|
-
"
|
|
2679
|
+
const footer = confirming ? [
|
|
2680
|
+
h("button", {
|
|
2681
|
+
type: "button",
|
|
2682
|
+
key: "cancel",
|
|
2683
|
+
className: "dshsc-btn ghost",
|
|
2684
|
+
disabled: busy,
|
|
2685
|
+
onClick: () => setConfirming(false)
|
|
2686
|
+
}, t("action.cancel")),
|
|
2687
|
+
h("button", {
|
|
2688
|
+
type: "button",
|
|
2689
|
+
key: "confirm",
|
|
2690
|
+
className: "dshsc-btn danger",
|
|
2691
|
+
disabled: busy,
|
|
2692
|
+
onClick: () => onSave("hidden")
|
|
2693
|
+
}, busy ? t("policy.saving") : t("policy.hiddenConfirm"))
|
|
2694
|
+
] : hidden ? [
|
|
2695
|
+
h("button", { type: "button", key: "cancel", className: "dshsc-btn ghost", onClick: onClose }, t("action.cancel")),
|
|
2696
|
+
h("button", {
|
|
2697
|
+
type: "button",
|
|
2698
|
+
key: "restore",
|
|
2699
|
+
className: "dshsc-btn primary",
|
|
2700
|
+
disabled: busy,
|
|
2701
|
+
onClick: onUnpark
|
|
2702
|
+
}, t("policy.unpark"))
|
|
2703
|
+
] : [
|
|
2704
|
+
h("button", { type: "button", key: "cancel", className: "dshsc-btn ghost", onClick: onClose }, t("action.cancel")),
|
|
2705
|
+
h("button", {
|
|
2706
|
+
type: "button",
|
|
2707
|
+
key: "save",
|
|
2708
|
+
className: "dshsc-btn primary",
|
|
2709
|
+
disabled: busy || !dirty || flat,
|
|
2710
|
+
onClick: submit
|
|
2711
|
+
}, busy ? t("policy.saving") : t("action.save"))
|
|
2712
|
+
];
|
|
2713
|
+
return h(
|
|
2714
|
+
Overlay,
|
|
2661
2715
|
{
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
style: { left: `${pos.left}px`, top: `${pos.top}px`, visibility: pos.visibility }
|
|
2716
|
+
t,
|
|
2717
|
+
title: t("policy.title"),
|
|
2718
|
+
onCancel: onClose,
|
|
2719
|
+
footer
|
|
2667
2720
|
},
|
|
2668
|
-
h(
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
"div",
|
|
2673
|
-
null,
|
|
2674
|
-
h("div", { className: "dshsc-policy-title" }, t("policy.title")),
|
|
2675
|
-
h("div", { className: "dshsc-policy-sub" }, t("policy.subtitle"))
|
|
2676
|
-
),
|
|
2677
|
-
h("button", {
|
|
2678
|
-
type: "button",
|
|
2679
|
-
className: "dshsc-policy-close",
|
|
2680
|
-
"aria-label": t("action.close"),
|
|
2681
|
-
onClick: onClose
|
|
2682
|
-
}, "×")
|
|
2683
|
-
),
|
|
2684
|
-
author ? h("div", { className: "dshsc-policy-note author" }, t("policy.authorHint")) : null,
|
|
2685
|
-
row.legacy ? h("div", { className: "dshsc-policy-note" }, t("policy.legacyHint")) : null,
|
|
2686
|
-
row.drift ? h("div", { className: "dshsc-policy-note warn" }, t("policy.driftHint")) : null,
|
|
2721
|
+
h("p", { className: "dshsc-sub", key: "sub" }, t("policy.subtitle")),
|
|
2722
|
+
author ? h("div", { className: "dshsc-policy-note author", key: "author" }, t("policy.authorHint")) : null,
|
|
2723
|
+
row.legacy ? h("div", { className: "dshsc-policy-note", key: "legacy" }, t("policy.legacyHint")) : null,
|
|
2724
|
+
row.drift ? h("div", { className: "dshsc-policy-note warn", key: "drift" }, t("policy.driftHint")) : null,
|
|
2687
2725
|
hidden ? h(
|
|
2688
2726
|
"div",
|
|
2689
|
-
{ className: "dshsc-policy-hidden" },
|
|
2727
|
+
{ className: "dshsc-policy-hidden", key: "hidden" },
|
|
2690
2728
|
h(
|
|
2691
2729
|
"div",
|
|
2692
|
-
{ className: "dshsc-
|
|
2693
|
-
h("span", { className: "dshsc-policyopt-dot" }),
|
|
2730
|
+
{ className: "dshsc-panel" },
|
|
2694
2731
|
h(
|
|
2695
|
-
"
|
|
2696
|
-
{ className: "dshsc-policyopt-
|
|
2697
|
-
h("
|
|
2698
|
-
h(
|
|
2732
|
+
"div",
|
|
2733
|
+
{ className: "dshsc-policyopt active static", role: "radio", "aria-checked": "true" },
|
|
2734
|
+
h("span", { className: "dshsc-policyopt-dot", "aria-hidden": "true" }),
|
|
2735
|
+
h(
|
|
2736
|
+
"span",
|
|
2737
|
+
{ className: "dshsc-policyopt-body" },
|
|
2738
|
+
h("b", null, t("policy.hidden")),
|
|
2739
|
+
h("small", null, t("policy.hiddenDesc"))
|
|
2740
|
+
)
|
|
2699
2741
|
)
|
|
2700
2742
|
),
|
|
2701
|
-
h("
|
|
2702
|
-
type: "button",
|
|
2703
|
-
className: "dshsc-btn primary dshsc-policy-restore",
|
|
2704
|
-
disabled: busy,
|
|
2705
|
-
onClick: onUnpark
|
|
2706
|
-
}, t("policy.unpark")),
|
|
2707
|
-
h("p", { className: "dshsc-policy-sub" }, t("policy.hiddenHint"))
|
|
2743
|
+
h("p", { className: "dshsc-sub" }, t("policy.hiddenHint"))
|
|
2708
2744
|
) : h(
|
|
2709
2745
|
"div",
|
|
2710
|
-
{ className: "dshsc-policy-options" },
|
|
2746
|
+
{ className: "dshsc-panel dshsc-policy-options", key: "options", role: "radiogroup", "aria-label": t("policy.title") },
|
|
2711
2747
|
option("auto", t("policy.auto"), t("policy.autoDesc")),
|
|
2712
2748
|
option("manual", t("policy.manual"), t("policy.manualDesc")),
|
|
2713
2749
|
option("hidden", t("policy.hidden"), t("policy.hiddenDesc"))
|
|
2714
2750
|
),
|
|
2715
2751
|
confirming ? h(
|
|
2716
2752
|
"div",
|
|
2717
|
-
{ className: "dshsc-policy-confirm" },
|
|
2753
|
+
{ className: "dshsc-policy-confirm", key: "confirm" },
|
|
2718
2754
|
h("b", null, t("policy.hiddenConfirmTitle")),
|
|
2719
|
-
h("p", null, t("policy.hiddenConfirmBody"))
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
{ className: "dshsc-policy-foot" },
|
|
2723
|
-
h("button", {
|
|
2724
|
-
type: "button",
|
|
2725
|
-
className: "dshsc-btn ghost",
|
|
2726
|
-
disabled: busy,
|
|
2727
|
-
onClick: () => setConfirming(false)
|
|
2728
|
-
}, t("action.cancel")),
|
|
2729
|
-
h("button", {
|
|
2730
|
-
type: "button",
|
|
2731
|
-
className: "dshsc-btn danger",
|
|
2732
|
-
disabled: busy,
|
|
2733
|
-
onClick: () => onSave("hidden")
|
|
2734
|
-
}, busy ? t("policy.saving") : t("policy.hiddenConfirm"))
|
|
2735
|
-
)
|
|
2736
|
-
) : h(
|
|
2737
|
-
"div",
|
|
2738
|
-
{ className: "dshsc-policy-foot" },
|
|
2739
|
-
h("button", { type: "button", className: "dshsc-btn ghost", onClick: onClose }, t("action.cancel")),
|
|
2740
|
-
hidden ? null : h("button", {
|
|
2741
|
-
type: "button",
|
|
2742
|
-
className: "dshsc-btn primary",
|
|
2743
|
-
disabled: busy || !dirty || flat,
|
|
2744
|
-
onClick: submit
|
|
2745
|
-
}, busy ? t("policy.saving") : t("action.save"))
|
|
2746
|
-
)
|
|
2747
|
-
), overlayHost());
|
|
2755
|
+
h("p", null, t("policy.hiddenConfirmBody"))
|
|
2756
|
+
) : null
|
|
2757
|
+
);
|
|
2748
2758
|
}
|
|
2749
2759
|
|
|
2750
2760
|
// client/views/installed.js
|
|
@@ -2788,16 +2798,10 @@ function InstalledTab({
|
|
|
2788
2798
|
anchor: { left: rect.left, top: rect.top, bottom: rect.bottom, width: rect.width, height: rect.height }
|
|
2789
2799
|
});
|
|
2790
2800
|
}
|
|
2791
|
-
function openPolicy(
|
|
2801
|
+
function openPolicy(row) {
|
|
2792
2802
|
if (busy !== null || row.kind === "file") return;
|
|
2793
2803
|
if (row.mode === "manual" && row.origin === "author") return;
|
|
2794
|
-
|
|
2795
|
-
const rect = el.getBoundingClientRect();
|
|
2796
|
-
setPolicy({
|
|
2797
|
-
row,
|
|
2798
|
-
anchorEl: el,
|
|
2799
|
-
anchor: { left: rect.left, top: rect.top, bottom: rect.bottom, width: rect.width, height: rect.height }
|
|
2800
|
-
});
|
|
2804
|
+
setPolicy({ row });
|
|
2801
2805
|
}
|
|
2802
2806
|
function policyChip(row) {
|
|
2803
2807
|
if (row.status === "unmanaged") {
|
|
@@ -2814,7 +2818,7 @@ function InstalledTab({
|
|
|
2814
2818
|
disabled: busy !== null,
|
|
2815
2819
|
title: t("policy.hiddenHint"),
|
|
2816
2820
|
"aria-haspopup": "dialog",
|
|
2817
|
-
onClick: (
|
|
2821
|
+
onClick: () => openPolicy(row)
|
|
2818
2822
|
}, t("policy.hidden"));
|
|
2819
2823
|
}
|
|
2820
2824
|
if (mode === "manual" && row.origin === "author") {
|
|
@@ -2830,7 +2834,7 @@ function InstalledTab({
|
|
|
2830
2834
|
disabled: busy !== null,
|
|
2831
2835
|
title: t("policy.driftHint"),
|
|
2832
2836
|
"aria-haspopup": "dialog",
|
|
2833
|
-
onClick: (
|
|
2837
|
+
onClick: () => openPolicy(row)
|
|
2834
2838
|
}, t("policy.drift"));
|
|
2835
2839
|
}
|
|
2836
2840
|
if (row.legacy === "dsh-off") {
|
|
@@ -2840,7 +2844,7 @@ function InstalledTab({
|
|
|
2840
2844
|
disabled: busy !== null,
|
|
2841
2845
|
title: t("policy.legacyHint"),
|
|
2842
2846
|
"aria-haspopup": "dialog",
|
|
2843
|
-
onClick: (
|
|
2847
|
+
onClick: () => openPolicy(row)
|
|
2844
2848
|
}, t("policy.legacy"));
|
|
2845
2849
|
}
|
|
2846
2850
|
if (mode === "manual") {
|
|
@@ -2850,7 +2854,7 @@ function InstalledTab({
|
|
|
2850
2854
|
disabled: busy !== null,
|
|
2851
2855
|
title: t("policy.manualOnlyHint"),
|
|
2852
2856
|
"aria-haspopup": "dialog",
|
|
2853
|
-
onClick: (
|
|
2857
|
+
onClick: () => openPolicy(row)
|
|
2854
2858
|
}, t("policy.manual"));
|
|
2855
2859
|
}
|
|
2856
2860
|
return h("button", {
|
|
@@ -2859,7 +2863,7 @@ function InstalledTab({
|
|
|
2859
2863
|
disabled: busy !== null,
|
|
2860
2864
|
title: t("policy.open"),
|
|
2861
2865
|
"aria-haspopup": "dialog",
|
|
2862
|
-
onClick: (
|
|
2866
|
+
onClick: () => openPolicy(row)
|
|
2863
2867
|
}, t("policy.auto"));
|
|
2864
2868
|
}
|
|
2865
2869
|
function statusTag(row) {
|
|
@@ -3256,11 +3260,9 @@ function InstalledTab({
|
|
|
3256
3260
|
actions.onView(target);
|
|
3257
3261
|
}
|
|
3258
3262
|
}) : null;
|
|
3259
|
-
const
|
|
3263
|
+
const policyModal = policy ? h(PolicyModal, {
|
|
3260
3264
|
t,
|
|
3261
3265
|
row: policy.row,
|
|
3262
|
-
anchor: policy.anchor,
|
|
3263
|
-
anchorEl: policy.anchorEl,
|
|
3264
3266
|
busy: busy !== null,
|
|
3265
3267
|
onClose: () => setPolicy(null),
|
|
3266
3268
|
onSave: (mode) => {
|
|
@@ -3274,7 +3276,7 @@ function InstalledTab({
|
|
|
3274
3276
|
actions.onRequestUnpark(target);
|
|
3275
3277
|
}
|
|
3276
3278
|
}) : null;
|
|
3277
|
-
return h(import_react5.default.Fragment, null, content(),
|
|
3279
|
+
return h(import_react5.default.Fragment, null, content(), policyModal, introPopover);
|
|
3278
3280
|
}
|
|
3279
3281
|
|
|
3280
3282
|
// client/views/agent-tip.js
|
|
@@ -3511,7 +3513,6 @@ function SubscriptionsTab({
|
|
|
3511
3513
|
h(
|
|
3512
3514
|
"span",
|
|
3513
3515
|
{ className: `dshsc-state${installedAlready ? " ok" : ""}` },
|
|
3514
|
-
installedAlready ? "✓ " : "",
|
|
3515
3516
|
installedAlready ? t("installed") : t("notInstalled")
|
|
3516
3517
|
),
|
|
3517
3518
|
h(
|
|
@@ -3539,34 +3540,6 @@ var import_react8 = __toESM(require("react"), 1);
|
|
|
3539
3540
|
|
|
3540
3541
|
// client/views/add-skill.js
|
|
3541
3542
|
var import_react7 = __toESM(require("react"), 1);
|
|
3542
|
-
|
|
3543
|
-
// client/views/overlay.js
|
|
3544
|
-
function Overlay({ t, title, children, footer, onCancel }) {
|
|
3545
|
-
useOverlayLayer(true, onCancel);
|
|
3546
|
-
return portalize(h(
|
|
3547
|
-
"div",
|
|
3548
|
-
{ className: "dshsc-overlay", onClick: (event) => {
|
|
3549
|
-
if (event.target === event.currentTarget) onCancel?.();
|
|
3550
|
-
} },
|
|
3551
|
-
h(
|
|
3552
|
-
"div",
|
|
3553
|
-
{ className: "dshsc-modal", role: "dialog", "aria-modal": "true" },
|
|
3554
|
-
h("button", {
|
|
3555
|
-
className: "dshsc-modal-close",
|
|
3556
|
-
"aria-label": t("action.cancel"),
|
|
3557
|
-
onClick: (event) => {
|
|
3558
|
-
event.stopPropagation();
|
|
3559
|
-
onCancel?.();
|
|
3560
|
-
}
|
|
3561
|
-
}, "×"),
|
|
3562
|
-
h("h3", null, title),
|
|
3563
|
-
children,
|
|
3564
|
-
h("div", { className: "dshsc-modal-foot" }, footer)
|
|
3565
|
-
)
|
|
3566
|
-
), overlayHost());
|
|
3567
|
-
}
|
|
3568
|
-
|
|
3569
|
-
// client/views/add-skill.js
|
|
3570
3543
|
function AddSkillModal({ t, onCancel, onProbe, onInstall }) {
|
|
3571
3544
|
const [source, setSource] = import_react7.default.useState("");
|
|
3572
3545
|
const [phase, setPhase] = import_react7.default.useState("idle");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morehao/dsh-skills-console",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "统一管理本地技能的安装、更新、删除与接入,让同一份技能在多个 Agent 间复用。A skill manager for DeepSeek Harness: install, update, remove, link and toggle agent skills.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "morehao <morehao@qq.com>",
|