prompt-skill-armory 0.10.0 → 0.10.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.en.md CHANGED
@@ -12,13 +12,13 @@
12
12
  |--|--|--|--|
13
13
  | <img src="docs/preview/preview-6.png" width="220"/> | <img src="docs/preview/preview-7.png" width="220"/> | | |
14
14
 
15
- ![version](https://img.shields.io/badge/version-0.10.0-00ff9c)
15
+ ![version](https://img.shields.io/badge/version-0.10.2-00ff9c)
16
16
  ![license](https://img.shields.io/badge/license-MIT-blue)
17
17
  ![platform](https://img.shields.io/badge/platform-web%20%2B%20desktop-00ff9c)
18
18
  ![CI](https://github.com/Qian-Ning/prompt-skill-armory/actions/workflows/ci.yml/badge.svg)
19
19
 
20
20
  ```
21
- ✦ Armory v0.10.0
21
+ ✦ Armory v0.10.2
22
22
  ┌─────────┬─────────┬─────┬────────────┬──────┬──────┐
23
23
  │ Prompts │ Skills │ MCP │ Wallpaper │ Chat │ Stats│
24
24
  │ global │ merged │ hub │ wallpaper │ sync │ usage│
@@ -125,7 +125,7 @@ Achieved via profile composition (the installer mounts the panel into each profi
125
125
 
126
126
  Every time the panel opens it queries npm for the latest `prompt-skill-armory` version; when a newer version exists a banner appears:
127
127
 
128
- > New version vX.Y.Z (current v0.10.0) [Update now]
128
+ > New version vX.Y.Z (current v0.10.2) [Update now]
129
129
 
130
130
  Clicking "Update now" makes the Host re-run the official installer in place → "Update complete, please restart the client".
131
131
 
package/README.md CHANGED
@@ -12,13 +12,13 @@
12
12
  |--|--|--|--|
13
13
  | <img src="docs/preview/preview-6.png" width="220"/> | <img src="docs/preview/preview-7.png" width="220"/> | | |
14
14
 
15
- ![version](https://img.shields.io/badge/version-0.10.0-00ff9c)
15
+ ![version](https://img.shields.io/badge/version-0.10.2-00ff9c)
16
16
  ![license](https://img.shields.io/badge/license-MIT-blue)
17
17
  ![platform](https://img.shields.io/badge/platform-web%20%2B%20desktop-00ff9c)
18
18
  ![CI](https://github.com/Qian-Ning/prompt-skill-armory/actions/workflows/ci.yml/badge.svg)
19
19
 
20
20
  ```
21
- ✦ Armory v0.10.0
21
+ ✦ Armory v0.10.2
22
22
  ┌─────────┬─────────┬─────┬────────────┬──────┬──────┐
23
23
  │ 提示词 │ 技能 │ MCP │ Wallpaper │ 对话 │ 统计 │
24
24
  │ 全局注入 │ 合并管理 │ 连接 │ 壁纸·特效 │ 导入 │ 用量 │
@@ -128,7 +128,7 @@ pnpm dsh web
128
128
 
129
129
  插件面板每次打开会自动查询 npm 上 `prompt-skill-armory` 的最新版本;发现新版本时顶部显示横幅:
130
130
 
131
- > 有新版本 vX.Y.Z(当前 v0.10.0) [一键更新]
131
+ > 有新版本 vX.Y.Z(当前 v0.10.2) [一键更新]
132
132
 
133
133
  点击「一键更新」→ Host 端运行官方安装器原地重装 → 提示「更新完成,请重启客户端生效」。
134
134
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prompt-skill-armory",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
4
4
  "description": "One-command installer for Prompt-SkillArmory (prompts + skills manager) into the DeepSeek Harness (web + desktop)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -155,14 +155,26 @@ window.__ModuleLoader__.load({
155
155
  const GLASS_ATTR = "data-ar-glass";
156
156
  const CSS_TAG = "prompt-skill-armory/background";
157
157
  const BACKGROUND_CSS = `
158
- .ar-bg-layer { position: fixed; inset: 0; z-index: -2; overflow: hidden; pointer-events: none; }
158
+ /* Backdrop pinned to the viewport at the very bottom of the stacking order.
159
+ z-index 0 + forcing DSH surfaces transparent lets it show through every
160
+ chrome (sidebar / conversation / rightbar), not just the chat area. */
161
+ .ar-bg-layer { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
159
162
  .ar-bg-layer .ar-bg-image { width: 100%; height: 100%; display: block; border: 0;
160
163
  object-fit: var(--ar-bg-fit, cover); opacity: var(--ar-bg-opacity, 1);
161
164
  filter: blur(var(--ar-bg-blur, 0px)); transform: scale(var(--ar-bg-scale, 1)); transform-origin: center; }
162
- .ar-bg-scrim { position: fixed; inset: 0; z-index: -1; pointer-events: none;
165
+ .ar-bg-scrim { position: fixed; inset: 0; z-index: 0; pointer-events: none;
163
166
  background: rgba(255,255,255, var(--ar-bg-scrim, 0.25)); }
164
167
  body[data-ds-dark-theme] .ar-bg-scrim { background: rgba(0,0,0, var(--ar-bg-scrim, 0.25)); }
165
- body[${ACTIVE_ATTR}] { --dsw-alias-bg-base: transparent; --dsw-specific-sidebar-fill: transparent; }
168
+
169
+ /* Lift the app chrome above the backdrop so it stays interactive, while
170
+ every DSH surface background becomes transparent to reveal the wallpaper. */
171
+ body[${ACTIVE_ATTR}] #root { position: relative; z-index: 1; background: transparent; }
172
+ body[${ACTIVE_ATTR}] .dshDesktopFrame,
173
+ body[${ACTIVE_ATTR}] .dshDesktopConversationSurface,
174
+ body[${ACTIVE_ATTR}] .dshDesktopSidebarSurface,
175
+ body[${ACTIVE_ATTR}] .dshDesktopRightbarSurface { background: transparent !important; }
176
+ body[${ACTIVE_ATTR}] { --dsw-alias-bg-base: transparent; --dsw-alias-bg-layer-1: transparent; --dsw-specific-sidebar-fill: transparent; }
177
+
166
178
  body[${GLASS_ATTR}] [data-composer-card],
167
179
  body[${GLASS_ATTR}] [class*="_bubble"]:not([role="tooltip"]),
168
180
  body[${GLASS_ATTR}] .md-code-block,
@@ -230,7 +242,11 @@ window.__ModuleLoader__.load({
230
242
  try {
231
243
  injectBackgroundCss();
232
244
  const hasSource = settings.url !== "" || settings.uploadId !== "";
233
- for (const prop of ["--dsw-alias-bg-base", "--dsw-specific-sidebar-fill"]) {
245
+ for (const prop of [
246
+ "--dsw-alias-bg-base",
247
+ "--dsw-alias-bg-layer-1",
248
+ "--dsw-specific-sidebar-fill"
249
+ ]) {
234
250
  this.rememberOnce(prop);
235
251
  document.body.style.setProperty(prop, "transparent");
236
252
  }
@@ -357,17 +373,17 @@ window.__ModuleLoader__.load({
357
373
  const notifyBg = () => {
358
374
  for (const l of bgListeners) l();
359
375
  };
360
- let bgApi;
361
- /** Bind the transport to a live connection API (set once at plugin apply). */
362
- function initBackgroundClient(api) {
363
- bgApi = api;
376
+ let bgScope;
377
+ /** Bind the transport to the switchblade settings scope (set once at plugin apply). */
378
+ function initBackgroundClient(scope) {
379
+ bgScope = scope;
364
380
  }
365
381
  /** Surface key: separate wallpaper per web vs desktop (they share the settings doc). */
366
382
  const isDesktopSurface = typeof navigator !== "undefined" && navigator.userAgent.toLowerCase().includes("electron");
367
383
  const surfaceKey = () => isDesktopSurface ? "backgroundDesktop" : "backgroundWeb";
368
384
  /** Read the background section for the current surface from the switchblade settings. */
369
385
  function readSection(value) {
370
- const raw = (value.namespaces?.find((n) => n.ns === "switchblade")?.value)?.[surfaceKey()];
386
+ const raw = value?.[surfaceKey()];
371
387
  return {
372
388
  ...DEFAULT_BACKGROUND,
373
389
  ...typeof raw === "object" && raw !== null ? raw : {}
@@ -385,15 +401,15 @@ window.__ModuleLoader__.load({
385
401
  },
386
402
  /** Fetch the durable section. @returns true on success (status ready). */
387
403
  async load() {
388
- if (bgApi === void 0) {
404
+ if (bgScope === void 0) {
389
405
  bgState.status = "error";
390
406
  return false;
391
407
  }
392
408
  try {
393
- const res = await bgApi.settings.describe({});
394
- if (!res.result.ok) throw new Error(res.result.error.message);
409
+ const snap = bgScope.getSnapshot();
410
+ if (snap.status !== "ready" || snap.value === void 0) return false;
395
411
  bgState.status = "ready";
396
- bgState.value = readSection(res.result.value);
412
+ bgState.value = readSection(snap.value);
397
413
  notifyBg();
398
414
  return true;
399
415
  } catch {
@@ -402,17 +418,13 @@ window.__ModuleLoader__.load({
402
418
  }
403
419
  },
404
420
  async save(section) {
405
- if (bgApi === void 0) return;
421
+ if (bgScope === void 0) return;
406
422
  try {
407
- const res = await bgApi.settings.mutate({
408
- ns: "switchblade",
409
- ops: [{
410
- op: "set",
411
- path: [surfaceKey()],
412
- value: section
413
- }]
414
- });
415
- if (!res.result.ok) throw new Error(res.result.error.message);
423
+ await bgScope.mutate([{
424
+ op: "set",
425
+ path: [surfaceKey()],
426
+ value: section
427
+ }]);
416
428
  bgState.status = "ready";
417
429
  bgState.value = { ...section };
418
430
  } catch {
@@ -449,7 +461,10 @@ window.__ModuleLoader__.load({
449
461
  applyHintStyle();
450
462
  }
451
463
  let hintObserver;
452
- /** Inject (or clear) the per-surface style for the composer's hint row + dock stats line. */
464
+ /** Inject (or clear) the per-surface style for the composer hint + input card.
465
+ * DSH 2.0.9 removed the old `[data-decoration="hint"]` row; the composer card
466
+ * (`[data-composer-card]`) is the stable surface that carries the input
467
+ * placeholder and inline claim hints, so the style lands there. */
453
468
  function applyHintStyle() {
454
469
  try {
455
470
  const hint = (bgState.value ?? DEFAULT_BACKGROUND).hint ?? DEFAULT_BACKGROUND.hint;
@@ -470,7 +485,15 @@ window.__ModuleLoader__.load({
470
485
  const size = hint.size || 11;
471
486
  const gradPreset = GRADIENTS.find((g) => g.id === (hint.gradient ?? ""));
472
487
  const grad = gradPreset !== void 0 ? gradPreset.css : "";
473
- let hintCss = `[data-decoration="hint"]{font-size:${size}px;letter-spacing:0.3px;font-weight:600;opacity:0.95;`;
488
+ const props = [
489
+ "font-size:" + size + "px",
490
+ "letter-spacing:0.3px",
491
+ "font-weight:600",
492
+ "opacity:0.95",
493
+ grad !== "" ? `background-image:${grad};-webkit-background-clip:text;background-clip:text;color:transparent` : `color:${color}`
494
+ ].join(";");
495
+ tag.textContent = `[data-composer-card] input::placeholder,[data-composer-card] textarea::placeholder{${props}}
496
+ [data-composer-card] [class*="_hint"]{${props}}`;
474
497
  const statsStyle = (root) => {
475
498
  if (grad !== "") {
476
499
  root.style.backgroundImage = grad;
@@ -487,10 +510,6 @@ window.__ModuleLoader__.load({
487
510
  root.style.fontWeight = "600";
488
511
  root.style.opacity = "0.95";
489
512
  };
490
- if (grad !== "") hintCss += `background-image:${grad};-webkit-background-clip:text;background-clip:text;color:transparent`;
491
- else hintCss += `color:${color}`;
492
- hintCss += "}";
493
- tag.textContent = hintCss;
494
513
  const applyStats = () => {
495
514
  try {
496
515
  const seps = Array.from(document.querySelectorAll("span[aria-hidden]"));
@@ -957,7 +976,7 @@ window.__ModuleLoader__.load({
957
976
  });
958
977
  }
959
978
  /** Bump with every release; keep in sync with package.json version + CHANGELOG. */
960
- const ARMORY_VERSION = "0.10.0";
979
+ const ARMORY_VERSION = "0.10.2";
961
980
  /** Compact duration: 45.2s / 2m42s / 1h05m. */
962
981
  function fmtDuration(ms) {
963
982
  const s = ms / 1e3;
@@ -3240,14 +3259,27 @@ window.__ModuleLoader__.load({
3240
3259
  return error instanceof Error ? error.message : String(error);
3241
3260
  }
3242
3261
  var SwitchbladeSectionController = class {
3243
- api;
3262
+ scope;
3263
+ remote;
3244
3264
  sessionId;
3245
3265
  /** Snapshot store backing the section's view state. */
3246
3266
  store = createSnapshotStore(IDLE);
3247
- constructor(api, sessionId) {
3248
- this.api = api;
3267
+ constructor(scope, remote, sessionId) {
3268
+ this.scope = scope;
3269
+ this.remote = remote;
3249
3270
  this.sessionId = sessionId;
3250
3271
  }
3272
+ /** 2.0.9 settings read: scope mirror snapshot (never the old api.settings). */
3273
+ describeSettings() {
3274
+ const snap = this.scope.getSnapshot();
3275
+ if (snap.status !== "ready" || snap.value === void 0) return void 0;
3276
+ return this.sectionFromSettings(snap.value, "switchblade");
3277
+ }
3278
+ /** 2.0.9 settings write: scope.mutate(ops) — Host fold + re-inject. */
3279
+ async mutateSettings(ops) {
3280
+ if (this.scope.getSnapshot().status !== "ready") throw new Error("settings scope not ready");
3281
+ await this.scope.mutate(ops);
3282
+ }
3251
3283
  /**
3252
3284
  * Load skills, prompts, and installed skills. Prompts and installed
3253
3285
  * skills come from the `switchblade` settings namespace (the Host watches
@@ -3260,16 +3292,14 @@ window.__ModuleLoader__.load({
3260
3292
  });
3261
3293
  try {
3262
3294
  const sessionId = this.sessionId?.();
3263
- const calls = [this.api.settings.describe({})];
3264
- if (sessionId !== void 0) calls.push(this.api.skills.list({ sessionId }));
3265
- const [settingsRes, skillRes] = await Promise.all(calls);
3266
- if (!settingsRes.result.ok) throw new Error(`settings.describe: ${settingsRes.result.error.message}`);
3267
- const skills = skillRes !== void 0 && skillRes.result.ok ? skillRes.result.value.skills.map((skill) => ({
3295
+ const calls = [Promise.resolve(this.describeSettings())];
3296
+ if (sessionId !== void 0) calls.push(this.remote.skills.list({ sessionId }));
3297
+ const [switchbladeSection, skillRes] = await Promise.all(calls);
3298
+ const skills = skillRes !== void 0 && skillRes.ok && skillRes.value !== void 0 ? skillRes.value.skills.map((skill) => ({
3268
3299
  name: skill.name,
3269
3300
  description: skill.description,
3270
3301
  modelInvocable: skill.modelInvocable
3271
3302
  })) : [];
3272
- const switchbladeSection = this.sectionFromSettings(settingsRes.result.value, "switchblade");
3273
3303
  const prompts = Array.isArray(switchbladeSection?.prompts) ? switchbladeSection.prompts : [];
3274
3304
  const installedSkills = Array.isArray(switchbladeSection?.installedSkills) ? switchbladeSection.installedSkills.map((s) => ({
3275
3305
  name: s.name ?? "",
@@ -3311,9 +3341,13 @@ window.__ModuleLoader__.load({
3311
3341
  });
3312
3342
  }
3313
3343
  }
3314
- /** Read one namespace's user section from a settings.describe value. */
3344
+ /** Read one namespace's section from a settings value. The 2.0.9 scope
3345
+ * snapshot carries the bound namespace's own value; older describe payloads
3346
+ * carry a `namespaces[]` table — accept both. */
3315
3347
  sectionFromSettings(value, ns) {
3316
3348
  if (typeof value !== "object" || value === null) return void 0;
3349
+ const asSection = value;
3350
+ if (Array.isArray(asSection.prompts) || Array.isArray(asSection.installedSkills) || asSection.mcpServers !== void 0) return asSection;
3317
3351
  const entries = value.namespaces;
3318
3352
  if (!Array.isArray(entries)) return void 0;
3319
3353
  for (const entry of entries) {
@@ -3326,24 +3360,20 @@ window.__ModuleLoader__.load({
3326
3360
  }
3327
3361
  /** Add a prompt. */
3328
3362
  async addPrompt(input) {
3329
- const res = await this.api.settings.mutate({
3330
- ns: "switchblade",
3331
- ops: [{
3332
- op: "set",
3333
- path: ["prompts"],
3334
- value: [...this.currentPrompts(), {
3335
- id: this.slugify(input.name),
3336
- name: input.name,
3337
- description: input.description,
3338
- content: input.content,
3339
- order: this.currentPrompts().length,
3340
- enabled: true,
3341
- isDefault: this.currentPrompts().length === 0,
3342
- ...input.scope === void 0 || input.scope.type === "global" ? {} : { scope: input.scope }
3343
- }]
3363
+ await this.mutateSettings([{
3364
+ op: "set",
3365
+ path: ["prompts"],
3366
+ value: [...this.currentPrompts(), {
3367
+ id: this.slugify(input.name),
3368
+ name: input.name,
3369
+ description: input.description,
3370
+ content: input.content,
3371
+ order: this.currentPrompts().length,
3372
+ enabled: true,
3373
+ isDefault: this.currentPrompts().length === 0,
3374
+ ...input.scope === void 0 || input.scope.type === "global" ? {} : { scope: input.scope }
3344
3375
  }]
3345
- });
3346
- if (!res.result.ok) throw new Error(res.result.error.message);
3376
+ }]);
3347
3377
  await this.load();
3348
3378
  }
3349
3379
  /** Toggle one prompt's enabled state. */
@@ -3380,15 +3410,11 @@ window.__ModuleLoader__.load({
3380
3410
  }
3381
3411
  /** Persist the prompt list through the settings RPC. */
3382
3412
  async writePrompts(prompts) {
3383
- const res = await this.api.settings.mutate({
3384
- ns: "switchblade",
3385
- ops: [{
3386
- op: "set",
3387
- path: ["prompts"],
3388
- value: prompts
3389
- }]
3390
- });
3391
- if (!res.result.ok) throw new Error(res.result.error.message);
3413
+ await this.mutateSettings([{
3414
+ op: "set",
3415
+ path: ["prompts"],
3416
+ value: prompts
3417
+ }]);
3392
3418
  await this.load();
3393
3419
  }
3394
3420
  /** Current prompt list from the loaded snapshot. */
@@ -3408,15 +3434,11 @@ window.__ModuleLoader__.load({
3408
3434
  content: input.content,
3409
3435
  enabled: true
3410
3436
  }];
3411
- const res = await this.api.settings.mutate({
3412
- ns: "switchblade",
3413
- ops: [{
3414
- op: "set",
3415
- path: ["installedSkills"],
3416
- value: next
3417
- }]
3418
- });
3419
- if (!res.result.ok) throw new Error(res.result.error.message);
3437
+ await this.mutateSettings([{
3438
+ op: "set",
3439
+ path: ["installedSkills"],
3440
+ value: next
3441
+ }]);
3420
3442
  await this.load();
3421
3443
  }
3422
3444
  /** Toggle one installed skill's enabled state. */
@@ -3425,29 +3447,21 @@ window.__ModuleLoader__.load({
3425
3447
  ...s,
3426
3448
  enabled
3427
3449
  } : s);
3428
- const res = await this.api.settings.mutate({
3429
- ns: "switchblade",
3430
- ops: [{
3431
- op: "set",
3432
- path: ["installedSkills"],
3433
- value: next
3434
- }]
3435
- });
3436
- if (!res.result.ok) throw new Error(res.result.error.message);
3450
+ await this.mutateSettings([{
3451
+ op: "set",
3452
+ path: ["installedSkills"],
3453
+ value: next
3454
+ }]);
3437
3455
  await this.load();
3438
3456
  }
3439
3457
  /** Uninstall one installed skill. */
3440
3458
  async uninstallSkill(name) {
3441
3459
  const next = this.currentInstalledSkills().filter((s) => s.name !== name);
3442
- const res = await this.api.settings.mutate({
3443
- ns: "switchblade",
3444
- ops: [{
3445
- op: "set",
3446
- path: ["installedSkills"],
3447
- value: next
3448
- }]
3449
- });
3450
- if (!res.result.ok) throw new Error(res.result.error.message);
3460
+ await this.mutateSettings([{
3461
+ op: "set",
3462
+ path: ["installedSkills"],
3463
+ value: next
3464
+ }]);
3451
3465
  await this.load();
3452
3466
  }
3453
3467
  /** Update an installed skill's name/description/content. */
@@ -3458,15 +3472,11 @@ window.__ModuleLoader__.load({
3458
3472
  description: patch.description ?? s.description,
3459
3473
  content: patch.content ?? s.content
3460
3474
  } : s);
3461
- const res = await this.api.settings.mutate({
3462
- ns: "switchblade",
3463
- ops: [{
3464
- op: "set",
3465
- path: ["installedSkills"],
3466
- value: next
3467
- }]
3468
- });
3469
- if (!res.result.ok) throw new Error(res.result.error.message);
3475
+ await this.mutateSettings([{
3476
+ op: "set",
3477
+ path: ["installedSkills"],
3478
+ value: next
3479
+ }]);
3470
3480
  await this.load();
3471
3481
  }
3472
3482
  /** Current installed skills from the loaded snapshot. */
@@ -3478,18 +3488,14 @@ window.__ModuleLoader__.load({
3478
3488
  * watch sees pendingZip and installs it (skil-filesystem then discovers it).
3479
3489
  */
3480
3490
  async installSkillFromZip(name, dataBase64) {
3481
- const res = await this.api.settings.mutate({
3482
- ns: "switchblade",
3483
- ops: [{
3484
- op: "set",
3485
- path: ["pendingZip"],
3486
- value: {
3487
- name,
3488
- dataBase64
3489
- }
3490
- }]
3491
- });
3492
- if (!res.result.ok) throw new Error(res.result.error.message);
3491
+ await this.mutateSettings([{
3492
+ op: "set",
3493
+ path: ["pendingZip"],
3494
+ value: {
3495
+ name,
3496
+ dataBase64
3497
+ }
3498
+ }]);
3493
3499
  await new Promise((r) => setTimeout(r, 500));
3494
3500
  await this.load();
3495
3501
  }
@@ -3526,32 +3532,24 @@ window.__ModuleLoader__.load({
3526
3532
  * after a short delay so the panel shows the fresh tool list / error.
3527
3533
  */
3528
3534
  async testMcpServer(name) {
3529
- const res = await this.api.settings.mutate({
3530
- ns: "switchblade",
3531
- ops: [{
3532
- op: "set",
3533
- path: ["mcpTestRequest"],
3534
- value: {
3535
- serverName: name,
3536
- ts: Date.now()
3537
- }
3538
- }]
3539
- });
3540
- if (!res.result.ok) throw new Error(res.result.error.message);
3535
+ await this.mutateSettings([{
3536
+ op: "set",
3537
+ path: ["mcpTestRequest"],
3538
+ value: {
3539
+ serverName: name,
3540
+ ts: Date.now()
3541
+ }
3542
+ }]);
3541
3543
  await new Promise((r) => setTimeout(r, 2e3));
3542
3544
  await this.load();
3543
3545
  }
3544
3546
  /** Persist the MCP server config list. */
3545
3547
  async writeMcpServers(servers) {
3546
- const res = await this.api.settings.mutate({
3547
- ns: "switchblade",
3548
- ops: [{
3549
- op: "set",
3550
- path: ["mcpServers"],
3551
- value: servers
3552
- }]
3553
- });
3554
- if (!res.result.ok) throw new Error(res.result.error.message);
3548
+ await this.mutateSettings([{
3549
+ op: "set",
3550
+ path: ["mcpServers"],
3551
+ value: servers
3552
+ }]);
3555
3553
  await this.load();
3556
3554
  }
3557
3555
  /** Current MCP server list from the loaded snapshot. */
@@ -3561,11 +3559,19 @@ window.__ModuleLoader__.load({
3561
3559
  };
3562
3560
  //#endregion
3563
3561
  //#region src/client/index.ts
3562
+ /**
3563
+ * Switchblade management page, browser half: registers the `settings.section`
3564
+ * navigation entry and renders the edgelord panel from the connection RPC
3565
+ * state. Global scope (root) — one management seat for every session.
3566
+ * @module @deepseek-ai/dsh-client-ui-switchblade
3567
+ */
3564
3568
  /** Required services (cordis fiber inject). */
3565
3569
  const inject = [
3566
3570
  "slots",
3567
3571
  "locale",
3568
- "connection",
3572
+ "settingsScope",
3573
+ "remote",
3574
+ "remote.skills",
3569
3575
  "sessions"
3570
3576
  ];
3571
3577
  /**
@@ -3577,11 +3583,12 @@ window.__ModuleLoader__.load({
3577
3583
  zh,
3578
3584
  en
3579
3585
  }), "ui-switchblade: dictionaries");
3580
- const api = ctx.get("connection").api;
3586
+ const scope = ctx.get("settingsScope").bind({ namespace: "switchblade" });
3587
+ const remote = ctx.get("remote");
3581
3588
  const sessions = ctx.get("sessions");
3582
3589
  applyHintStyle();
3583
3590
  try {
3584
- initBackgroundClient(api);
3591
+ initBackgroundClient(scope);
3585
3592
  const paintBackground = () => {
3586
3593
  const s = backgroundClient.getSnapshot();
3587
3594
  if (s.status === "ready") applyBackground(s.value);
@@ -3596,7 +3603,7 @@ window.__ModuleLoader__.load({
3596
3603
  } catch (error) {
3597
3604
  console.warn("[switchblade] background init skipped:", error);
3598
3605
  }
3599
- const controller = new SwitchbladeSectionController(api, () => {
3606
+ const controller = new SwitchbladeSectionController(scope, remote, () => {
3600
3607
  const state = sessions.list.getSnapshot();
3601
3608
  return state.current === void 0 ? void 0 : state.current;
3602
3609
  });