dsh-agent-skills 0.1.1 → 0.1.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 CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  把 Claude Code、Codex、Gemini CLI、Cursor 等工具的本地 Agent Skills 接入 DeepSeek Harness,并在「设置 → Agent Skills」里统一查看、启停和管理。
8
8
 
9
+ ![Agent Skills 设置页面](https://raw.githubusercontent.com/minivv/dsh-agent-skills/main/agent-skills-page.png)
10
+
9
11
  ## 它解决什么问题
10
12
 
11
13
  很多 AI 编程工具都使用 `<技能名>/SKILL.md`,但技能分散在不同目录。`dsh-agent-skills` 会自动发现这些目录,把有效技能汇总进 DSH,并提供一个可视化设置页:
@@ -13,7 +15,7 @@
13
15
  - 默认扫描 `~/.agents/skills`、`~/.claude/skills`、`~/.codex/skills`、`~/.config/opencode/skills` 和 `~/.gemini/skills`。
14
16
  - 支持添加任意自定义技能目录。
15
17
  - 显示每个来源是否存在、包含多少有效技能,以及技能名称和描述。
16
- - 可按目录或单个技能启停;变更会持久化,并在下一次 Agent step 生效。
18
+ - 可按目录或单个技能启停;变更会持久化,页面会提示刷新后生效。
17
19
  - 监听技能文件变化,也可随时手动重新扫描。
18
20
  - 不修改原始 `SKILL.md` 文件。
19
21
 
@@ -21,9 +23,9 @@
21
23
 
22
24
  ### 方式一:DSH 插件市场(推荐)
23
25
 
24
- 打开 DSH 的「设置 → 插件市场」,搜索 **Agent Skills**,点击安装。市场会优先使用 npm 包,安装速度快,也不需要在本机重新构建。
26
+ 通过 [DSH 插件市场](https://github.com/dsh-market/dsh-market) 安装,或打开 DSH 的「设置 → 插件市场」,搜索 **Agent Skills**,点击安装。市场会优先使用 npm 包,安装速度快,也不需要在本机重新构建。
25
27
 
26
- 安装后继续完成下面的「启用技能开关」步骤,再重启 DSH Web。
28
+ 安装后继续完成下面的「开启接管 DSH 技能」步骤,再重启 DSH Web。
27
29
 
28
30
  ### 方式二:从 npm 安装
29
31
 
@@ -39,16 +41,24 @@ dsh plugin --profile web add github:minivv/dsh-agent-skills
39
41
 
40
42
  仓库包含 `prepare: npm run build`,因此 pnpm 会在 Git 安装时自动构建。DSH/pnpm 可能会要求你授权构建脚本;不想授权构建时请使用 npm 或插件市场版本,npm 包已经包含构建好的 `lib/`。
41
43
 
42
- ### 启用技能开关
44
+ ### 开启接管 DSH 技能
45
+
46
+ 完成任一种安装方式后:
47
+
48
+ 1. 打开 DSH 的「设置 → Agent Skills」。
49
+ 2. 点击 **开启接管 DSH 技能**。
50
+ 3. 看到“已开启”提示后重启 DSH Web。
51
+
52
+ 开启后,页面中的目录和技能开关会接入 `standard` 与 `code` preset,真正控制 Agent 可见的技能。这个操作只添加 `dsh-agent-skills/preset` provider,不会创建第二个 `agentSkills` host 服务。
43
53
 
44
- 完成任一种安装方式后,运行一次 preset 安装脚本,让技能开关覆盖 `standard` 和 `code` preset 自带的 filesystem provider:
54
+ 如果页面无法定位 DSH 安装位置,可以使用备用命令:
45
55
 
46
56
  ```bash
47
57
  DSH_INSTALL_ROOT="$(npm root -g)/@deepseek-ai/dsh" \
48
58
  node ~/.dsh/profiles/web/node_modules/dsh-agent-skills/scripts/install-preset.mjs
49
59
  ```
50
60
 
51
- 然后重启 DSH Web。这个 preset 入口只注册 scoped skill provider,不会在 Agent preset 中创建 `agentSkills` host 服务。DSH 升级可能覆盖内置 preset,若开关再次失效,重新运行这条命令即可。
61
+ 执行后重启 DSH Web。DSH 升级可能覆盖内置 preset;如果页面重新显示“开启接管 DSH 技能”,点击一次即可恢复。
52
62
 
53
63
  ## 使用
54
64
 
@@ -56,7 +66,8 @@ DSH_INSTALL_ROOT="$(npm root -g)/@deepseek-ai/dsh" \
56
66
  2. 进入「设置 → Agent Skills」。
57
67
  3. 检查自动发现的来源,或点击「+ 添加目录」。
58
68
  4. 使用来源开关或技能开关控制 Agent 可见范围。
59
- 5. 修改磁盘上的技能后,点击「重新扫描」或等待自动刷新。
69
+ 5. 技能区出现“n 个技能变更需刷新页面生效”后,点击「刷新页面」。
70
+ 6. 修改磁盘上的技能后,点击「重新扫描」或等待自动刷新。
60
71
 
61
72
  插件状态保存在:
62
73
 
@@ -117,13 +128,14 @@ npm pack --dry-run
117
128
  ## 已知约束
118
129
 
119
130
  - DSH 技能名必须匹配 `[a-z0-9]+(?:-[a-z0-9]+)*`。
120
- - 修改插件安装或 preset 组合后需要重启一次;技能启停和重新扫描不需要重启。
121
- - DSH 升级可能覆盖其内置 preset 文件;如开关不再生效,重新运行 `scripts/install-preset.mjs`。
131
+ - 修改插件安装或 preset 组合后需要重启一次;目录或技能开关变更后按页面提示刷新。
132
+ - DSH 升级可能覆盖其内置 preset 文件;如开关不再生效,在设置页重新点击「开启接管 DSH 技能」。
122
133
 
123
134
  ## 相关链接
124
135
 
125
136
  - [GitHub](https://github.com/minivv/dsh-agent-skills)
126
137
  - [npm](https://www.npmjs.com/package/dsh-agent-skills)
138
+ - [DSH 插件市场](https://github.com/dsh-market/dsh-market)
127
139
  - [WeiSpot 项目页](https://weispot.vercel.app/projects/dsh-agent-skills)
128
140
 
129
141
  ## License
package/lib/client.js CHANGED
@@ -36,6 +36,14 @@ var zh = {
36
36
  nav: "Agent Skills",
37
37
  title: "Agent Skills",
38
38
  subtitle: "\u6D4F\u89C8\u3001\u542F\u7528\u548C\u7BA1\u7406\u667A\u80FD\u4F53\u6280\u80FD\u4E0E\u6765\u6E90\u3002",
39
+ takeoverTitle: "\u63A5\u7BA1 DSH \u6280\u80FD",
40
+ takeoverDescription: "\u5F00\u542F\u540E\uFF0C\u8FD9\u91CC\u7684\u76EE\u5F55\u548C\u6280\u80FD\u5F00\u5173\u4F1A\u771F\u6B63\u63A7\u5236 Agent \u53EF\u89C1\u7684\u6280\u80FD\u3002",
41
+ takeoverEnabledTitle: "\u5DF2\u63A5\u7BA1 DSH \u6280\u80FD",
42
+ takeoverEnabledDescription: "\u76EE\u5F55\u548C\u6280\u80FD\u5F00\u5173\u5DF2\u63A5\u5165 standard \u4E0E code \u9884\u8BBE\u3002",
43
+ takeoverRestartDescription: "\u5DF2\u5F00\u542F\uFF0C\u8BF7\u91CD\u542F DSH \u540E\u751F\u6548\u3002",
44
+ takeoverPartialDescription: "\u5DF2\u63A5\u5165 {configured}/{total} \u4E2A\u9884\u8BBE\uFF0C\u70B9\u51FB\u7EE7\u7EED\u5B8C\u6210\u3002",
45
+ takeoverUnavailableDescription: "\u672A\u627E\u5230 DSH \u5B89\u88C5\u4F4D\u7F6E\uFF0C\u8BF7\u786E\u8BA4\u5F53\u524D\u9875\u9762\u7531 DSH \u542F\u52A8\u540E\u91CD\u8BD5\u3002",
46
+ takeoverAction: "\u5F00\u542F\u63A5\u7BA1 DSH \u6280\u80FD",
39
47
  searchPlaceholder: "\u641C\u7D22\u6280\u80FD\u540D\u79F0\u6216\u63CF\u8FF0\u2026",
40
48
  sources: "\u6765\u6E90",
41
49
  validCount: "\u4E2A\u6709\u6548",
@@ -53,6 +61,8 @@ var zh = {
53
61
  dirMissing: "\u76EE\u5F55\u4E0D\u5B58\u5728",
54
62
  enabledLabel: "\u6280\u80FD",
55
63
  enabledStats: "{total} \u4E2A\u53EF\u7528 \xB7 {custom} \u4E2A\u81EA\u5B9A\u4E49 \xB7 {global} \u4E2A\u5168\u5C40 \xB7 {builtin} \u4E2A\u5185\u7F6E",
64
+ refreshPending: "{n} \u4E2A\u6280\u80FD\u53D8\u66F4\u9700\u5237\u65B0\u9875\u9762\u751F\u6548",
65
+ refreshPage: "\u5237\u65B0\u9875\u9762",
56
66
  noSkills: "\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u7684\u6280\u80FD\u3002\u70B9\u51FB\u300C+ \u6DFB\u52A0\u76EE\u5F55\u300D\u6DFB\u52A0\u4E00\u4E2A\u6280\u80FD\u76EE\u5F55\uFF0C\u6216\u542F\u7528\u66F4\u591A\u6765\u6E90\u3002",
57
67
  noMatch: "\u6CA1\u6709\u5339\u914D\u7684\u6280\u80FD",
58
68
  tagCustom: "\u81EA\u5B9A\u4E49",
@@ -76,6 +86,14 @@ var en = {
76
86
  nav: "Agent Skills",
77
87
  title: "Agent Skills",
78
88
  subtitle: "Browse, enable, and manage agent skills and their sources.",
89
+ takeoverTitle: "Take over DSH skills",
90
+ takeoverDescription: "Connect these source and skill switches to the skills visible to the Agent.",
91
+ takeoverEnabledTitle: "DSH skills are managed here",
92
+ takeoverEnabledDescription: "Source and skill switches are connected to the standard and code presets.",
93
+ takeoverRestartDescription: "Enabled. Restart DSH to apply the change.",
94
+ takeoverPartialDescription: "Connected to {configured}/{total} presets. Continue to finish setup.",
95
+ takeoverUnavailableDescription: "DSH could not be located. Open this page from DSH and try again.",
96
+ takeoverAction: "Enable DSH skill takeover",
79
97
  searchPlaceholder: "Search skills by name or description\u2026",
80
98
  sources: "Sources",
81
99
  validCount: "valid",
@@ -93,6 +111,8 @@ var en = {
93
111
  dirMissing: "directory missing",
94
112
  enabledLabel: "Skills",
95
113
  enabledStats: "{total} available \xB7 {custom} custom \xB7 {global} global \xB7 {builtin} builtin",
114
+ refreshPending: "{n} skill changes need a page refresh to take effect",
115
+ refreshPage: "Refresh page",
96
116
  noSkills: "No skills available. Click \u201C+ Add directory\u201D to add a skill directory, or enable more sources.",
97
117
  noMatch: "No matching skills",
98
118
  tagCustom: "Custom",
@@ -182,6 +202,8 @@ function DirCard({
182
202
  }
183
203
  function AgentSkillsSection({ api, t }) {
184
204
  const [view, setView] = (0, import_react.useState)(void 0);
205
+ const [takeover, setTakeover] = (0, import_react.useState)(void 0);
206
+ const [takeoverRestartRequired, setTakeoverRestartRequired] = (0, import_react.useState)(false);
185
207
  const [busy, setBusy] = (0, import_react.useState)(true);
186
208
  const [error51, setError] = (0, import_react.useState)("");
187
209
  const [query, setQuery] = (0, import_react.useState)("");
@@ -190,31 +212,61 @@ function AgentSkillsSection({ api, t }) {
190
212
  const [addDirText, setAddDirText] = (0, import_react.useState)("");
191
213
  const [dirExpanded, setDirExpanded] = (0, import_react.useState)(/* @__PURE__ */ new Set());
192
214
  const [saving, setSaving] = (0, import_react.useState)(false);
215
+ const [pendingSkillCount, setPendingSkillCount] = (0, import_react.useState)(0);
216
+ const baselineEnabled = (0, import_react.useRef)(void 0);
217
+ const rememberBaseline = (0, import_react.useCallback)((next) => {
218
+ if (baselineEnabled.current !== void 0) return;
219
+ baselineEnabled.current = new Map(next.skills.map((skill) => [skill.name, skill.enabled]));
220
+ }, []);
221
+ const updatePendingCount = (0, import_react.useCallback)((next) => {
222
+ const baseline = baselineEnabled.current;
223
+ if (baseline === void 0) {
224
+ rememberBaseline(next);
225
+ setPendingSkillCount(0);
226
+ return;
227
+ }
228
+ let changed = 0;
229
+ for (const skill of next.skills) {
230
+ const initial = baseline.get(skill.name);
231
+ if (initial !== void 0 && initial !== skill.enabled) changed += 1;
232
+ }
233
+ setPendingSkillCount(changed);
234
+ }, [rememberBaseline]);
193
235
  const load = (0, import_react.useCallback)(async (refresh = () => api.list()) => {
194
236
  setError("");
195
237
  const result2 = await refresh();
196
238
  if (result2.ok) {
239
+ rememberBaseline(result2.value);
197
240
  setView(result2.value);
198
241
  } else {
199
242
  setError(t("errorLoad", { message: result2.error.message }));
200
243
  }
244
+ }, [api, rememberBaseline, t]);
245
+ const loadTakeover = (0, import_react.useCallback)(async (refresh = () => api.takeoverStatus()) => {
246
+ const result2 = await refresh();
247
+ if (result2.ok) {
248
+ setTakeover(result2.value);
249
+ } else {
250
+ setError(t("errorLoad", { message: result2.error.message }));
251
+ }
201
252
  }, [api, t]);
202
253
  (0, import_react.useEffect)(() => {
203
254
  setBusy(true);
204
- void load().finally(() => setBusy(false));
205
- }, [load]);
255
+ void Promise.all([load(), loadTakeover()]).finally(() => setBusy(false));
256
+ }, [load, loadTakeover]);
206
257
  (0, import_react.useEffect)(() => {
207
258
  const timer = window.setInterval(() => {
208
259
  void load();
209
260
  }, 5e3);
210
261
  return () => window.clearInterval(timer);
211
262
  }, [load]);
212
- const mutate = (0, import_react.useCallback)(async (operation) => {
263
+ const mutate = (0, import_react.useCallback)(async (operation, trackSkillChanges = false) => {
213
264
  setSaving(true);
214
265
  setError("");
215
266
  try {
216
267
  const result2 = await operation();
217
268
  if (result2.ok) {
269
+ if (trackSkillChanges) updatePendingCount(result2.value);
218
270
  setView(result2.value);
219
271
  } else {
220
272
  setError(t("errorSave", { message: result2.error.message }));
@@ -222,7 +274,22 @@ function AgentSkillsSection({ api, t }) {
222
274
  } finally {
223
275
  setSaving(false);
224
276
  }
225
- }, [t]);
277
+ }, [t, updatePendingCount]);
278
+ const enableTakeover = (0, import_react.useCallback)(async () => {
279
+ setSaving(true);
280
+ setError("");
281
+ try {
282
+ const result2 = await api.enableTakeover();
283
+ if (result2.ok) {
284
+ setTakeover(result2.value);
285
+ setTakeoverRestartRequired(result2.value.enabled);
286
+ } else {
287
+ setError(t("errorSave", { message: result2.error.message }));
288
+ }
289
+ } finally {
290
+ setSaving(false);
291
+ }
292
+ }, [api, t]);
226
293
  const toggleDirExpanded = (path) => {
227
294
  setDirExpanded((prev) => {
228
295
  const next = new Set(prev);
@@ -267,6 +334,14 @@ function AgentSkillsSection({ api, t }) {
267
334
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "as-wrap", "data-plugin": "dsh-agent-skills", children: [
268
335
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { className: "as-title", children: t("title") }),
269
336
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "as-subtitle", children: t("subtitle") }),
337
+ takeover !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: takeover.enabled ? "as-takeover as-takeover-enabled" : "as-takeover", children: [
338
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "as-takeover-icon", "aria-hidden": "true", children: takeover.enabled ? "\u2713" : "\u2192" }),
339
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "as-takeover-copy", children: [
340
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: takeover.enabled ? t("takeoverEnabledTitle") : t("takeoverTitle") }),
341
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: takeoverRestartRequired ? t("takeoverRestartDescription") : takeover.enabled ? t("takeoverEnabledDescription") : takeover.available && takeover.configured > 0 ? t("takeoverPartialDescription", { configured: takeover.configured, total: takeover.total }) : takeover.available ? t("takeoverDescription") : t("takeoverUnavailableDescription") })
342
+ ] }),
343
+ !takeover.enabled && takeover.available && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "as-btn as-btn-primary as-takeover-action", disabled: saving, onClick: () => void enableTakeover(), children: t("takeoverAction") })
344
+ ] }),
270
345
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
271
346
  "input",
272
347
  {
@@ -378,7 +453,7 @@ function AgentSkillsSection({ api, t }) {
378
453
  t,
379
454
  expanded: dirExpanded.has(dir.path),
380
455
  onToggleExpanded: () => toggleDirExpanded(dir.path),
381
- onToggleEnabled: (next) => void mutate(() => api.toggleDir({ path: dir.path, enabled: next })),
456
+ onToggleEnabled: (next) => void mutate(() => api.toggleDir({ path: dir.path, enabled: next }), true),
382
457
  onRemove: () => void mutate(() => api.removeDir({ path: dir.path }))
383
458
  },
384
459
  dir.path
@@ -392,6 +467,11 @@ function AgentSkillsSection({ api, t }) {
392
467
  builtin: view.counts.builtin
393
468
  }) })
394
469
  ] }),
470
+ pendingSkillCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "as-refresh-card", role: "status", children: [
471
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "as-refresh-icon", "aria-hidden": "true", children: "\u21BB" }),
472
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "as-refresh-message", children: t("refreshPending", { n: pendingSkillCount }) }),
473
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "as-btn as-refresh-action", onClick: () => window.location.reload(), children: t("refreshPage") })
474
+ ] }),
395
475
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "as-skill-grid", children: filteredSkills.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "as-empty", children: query.trim() === "" ? t("noSkills") : t("noMatch") }) : filteredSkills.map((skill) => {
396
476
  const tagClass = skill.kind === "custom" ? "as-tag-custom" : skill.kind === "builtin" ? "as-tag-builtin" : "as-tag-global";
397
477
  const tagLabel = skill.kind === "custom" ? t("tagCustom") : skill.kind === "builtin" ? t("tagBuiltin") : t("tagGlobal");
@@ -408,7 +488,7 @@ function AgentSkillsSection({ api, t }) {
408
488
  {
409
489
  checked: skill.enabled,
410
490
  disabled: saving || !skill.toggleable,
411
- onChange: (next) => void mutate(() => api.toggleSkill({ name: skill.name, enabled: next })),
491
+ onChange: (next) => void mutate(() => api.toggleSkill({ name: skill.name, enabled: next }), true),
412
492
  label: skill.enabled ? t("enabled") : t("disabled")
413
493
  }
414
494
  )
@@ -433,8 +513,11 @@ var CSS = `
433
513
  --as-accent: #3fb950;
434
514
  --as-accent-soft: rgba(63, 185, 80, 0.15);
435
515
  --as-danger: #f85149;
436
- --as-radius: 10px;
516
+ --as-warning: #d29922;
517
+ --as-warning-soft: rgba(210, 153, 34, 0.12);
518
+ --as-radius: 8px;
437
519
  color-scheme: light dark;
520
+ -webkit-font-smoothing: antialiased;
438
521
  }
439
522
 
440
523
  .as-wrap { display: flex; flex-direction: column; gap: 14px; width: 100%; max-width: 860px; }
@@ -443,6 +526,16 @@ var CSS = `
443
526
  .as-search { width: 100%; box-sizing: border-box; padding: 8px 12px; border-radius: 8px; border: 1px solid var(--as-border); background: transparent; color: inherit; font-size: 13px; outline: none; }
444
527
  .as-search:focus { border-color: var(--as-accent); }
445
528
 
529
+ .as-takeover { display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 9px 10px; border: 1px solid var(--as-border-soft); border-radius: var(--as-radius); background: rgba(128, 128, 128, 0.04); box-sizing: border-box; }
530
+ .as-takeover-enabled { border-color: rgba(63, 185, 80, 0.28); background: rgba(63, 185, 80, 0.07); }
531
+ .as-takeover-icon { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; flex: none; border-radius: 50%; background: rgba(128, 128, 128, 0.13); color: var(--as-muted); font-size: 14px; font-weight: 650; }
532
+ .as-takeover-enabled .as-takeover-icon { color: var(--as-accent); background: var(--as-accent-soft); }
533
+ .as-takeover-copy { display: flex; flex: 1; min-width: 0; flex-direction: column; gap: 2px; }
534
+ .as-takeover-copy strong { font-size: 13px; font-weight: 600; line-height: 1.35; text-wrap: balance; }
535
+ .as-takeover-copy span { font-size: 12px; line-height: 1.45; color: var(--as-muted); text-wrap: pretty; }
536
+ .as-takeover-action { min-height: 40px; flex: none; transition-property: transform, background-color; transition-duration: 120ms; }
537
+ .as-takeover-action:active:not(:disabled) { transform: scale(0.96); }
538
+
446
539
  .as-sources-row { display: flex; align-items: baseline; gap: 10px; }
447
540
  .as-sources-label { font-size: 14px; font-weight: 550; }
448
541
  .as-sources-counts { font-size: 12px; color: var(--as-muted); }
@@ -489,6 +582,12 @@ var CSS = `
489
582
  .as-skills-header { display: flex; align-items: baseline; gap: 7px; font-size: 13px; font-weight: 550; margin: 4px 0 0; text-wrap: balance; }
490
583
  .as-skills-header-title { color: var(--as-text); }
491
584
  .as-skills-header-stats { font-size: 11px; font-weight: 450; color: var(--as-muted-2); font-variant-numeric: tabular-nums; }
585
+ .as-refresh-card { display: flex; align-items: center; gap: 9px; min-height: 48px; padding: 4px 5px 4px 11px; border: 1px solid rgba(210, 153, 34, 0.28); border-radius: var(--as-radius); background: var(--as-warning-soft); box-sizing: border-box; }
586
+ .as-refresh-icon { flex: none; color: var(--as-warning); font-size: 17px; line-height: 1; }
587
+ .as-refresh-message { flex: 1; min-width: 0; color: var(--as-text); font-size: 12px; line-height: 1.45; font-variant-numeric: tabular-nums; text-wrap: pretty; }
588
+ .as-refresh-action { min-height: 40px; flex: none; border-color: rgba(210, 153, 34, 0.42); background: rgba(210, 153, 34, 0.08); transition-property: transform, background-color; transition-duration: 120ms; }
589
+ .as-refresh-action:hover { background: rgba(210, 153, 34, 0.14); }
590
+ .as-refresh-action:active { transform: scale(0.96); }
492
591
  .as-skill-grid { display: flex; flex-direction: column; gap: 8px; }
493
592
  .as-skill-card { border: 1px solid var(--as-border-soft); border-radius: var(--as-radius); padding: 10px 12px; display: flex; flex-direction: column; gap: 5px; }
494
593
  .as-skill-row { display: flex; align-items: center; gap: 8px; }
@@ -511,6 +610,43 @@ var CSS = `
511
610
  .as-empty { font-size: 12px; color: var(--as-muted); padding: 12px 0; }
512
611
  .as-error { font-size: 12px; color: var(--as-danger); }
513
612
  .as-busy { font-size: 12px; color: var(--as-muted-2); }
613
+
614
+ @media (max-width: 640px) {
615
+ [role="dialog"]:has([data-plugin="dsh-agent-skills"]) { flex-direction: column; }
616
+ [role="dialog"]:has([data-plugin="dsh-agent-skills"]) > nav {
617
+ width: 100%;
618
+ height: auto;
619
+ flex: none;
620
+ box-sizing: border-box;
621
+ border-right: 0;
622
+ border-bottom: 1px solid var(--as-border-soft);
623
+ }
624
+ [role="dialog"]:has([data-plugin="dsh-agent-skills"]) > nav > :first-child { display: none; }
625
+ [role="dialog"]:has([data-plugin="dsh-agent-skills"]) > nav > :last-child {
626
+ display: grid;
627
+ grid-template-columns: repeat(2, minmax(0, 1fr));
628
+ gap: 4px;
629
+ }
630
+ [role="dialog"]:has([data-plugin="dsh-agent-skills"]) > nav > :last-child > button {
631
+ min-width: 0;
632
+ padding-inline: 8px;
633
+ }
634
+ [role="dialog"]:has([data-plugin="dsh-agent-skills"]) > div {
635
+ width: 100%;
636
+ min-width: 0;
637
+ min-height: 0;
638
+ flex: 1;
639
+ }
640
+ .as-takeover { align-items: flex-start; flex-wrap: wrap; }
641
+ .as-takeover-action { width: 100%; }
642
+ .as-actions-row { flex-wrap: wrap; }
643
+ .as-dir-row { align-items: flex-start; flex-wrap: wrap; }
644
+ .as-dir-path { flex: 1; min-width: 120px; }
645
+ .as-skill-row { align-items: flex-start; flex-wrap: wrap; }
646
+ .as-refresh-card { flex-wrap: wrap; padding: 8px 9px; }
647
+ .as-refresh-message { min-width: calc(100% - 34px); }
648
+ .as-refresh-action { width: 100%; }
649
+ }
514
650
  `;
515
651
  var installed;
516
652
  function injectStyles() {
@@ -15098,6 +15234,16 @@ var agentSkillsViewSchema = external_exports.object({
15098
15234
  validDirs: external_exports.number().int().min(0),
15099
15235
  missingDirs: external_exports.number().int().min(0)
15100
15236
  });
15237
+ var presetTakeoverStatusSchema = external_exports.object({
15238
+ /** Whether a verified DSH install with supported presets was found. */
15239
+ available: external_exports.boolean(),
15240
+ /** Whether every available standard/code preset contains the managed row. */
15241
+ enabled: external_exports.boolean(),
15242
+ /** Number of preset files that already contain the managed row. */
15243
+ configured: external_exports.number().int().min(0),
15244
+ /** Number of supported preset files found in this DSH installation. */
15245
+ total: external_exports.number().int().min(0)
15246
+ });
15101
15247
  var toggleSkillInputSchema = external_exports.object({
15102
15248
  name: external_exports.string(),
15103
15249
  enabled: external_exports.boolean()
@@ -15134,6 +15280,24 @@ var TYPERT_REMOTE = {
15134
15280
  parameters: [],
15135
15281
  result: result("AgentSkillsView", agentSkillsViewSchema)
15136
15282
  },
15283
+ {
15284
+ id: `${PKG}#agentSkills/takeoverStatus`,
15285
+ service: "agentSkills",
15286
+ namespace: "agentSkills",
15287
+ method: "takeoverStatus",
15288
+ invocation: direct,
15289
+ parameters: [],
15290
+ result: result("PresetTakeoverStatus", presetTakeoverStatusSchema)
15291
+ },
15292
+ {
15293
+ id: `${PKG}#agentSkills/enableTakeover`,
15294
+ service: "agentSkills",
15295
+ namespace: "agentSkills",
15296
+ method: "enableTakeover",
15297
+ invocation: direct,
15298
+ parameters: [],
15299
+ result: result("PresetTakeoverStatus", presetTakeoverStatusSchema)
15300
+ },
15137
15301
  {
15138
15302
  id: `${PKG}#agentSkills/toggleSkill`,
15139
15303
  service: "agentSkills",