prompt-skill-armory 0.9.9 → 0.10.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/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.9.9-00ff9c)
15
+ ![version](https://img.shields.io/badge/version-0.10.1-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.9.9
21
+ ✦ Armory v0.10.1
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.9.9) [Update now]
128
+ > New version vX.Y.Z (current v0.10.1) [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.9.9-00ff9c)
15
+ ![version](https://img.shields.io/badge/version-0.10.1-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.9.9
21
+ ✦ Armory v0.10.1
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.9.9) [一键更新]
131
+ > 有新版本 vX.Y.Z(当前 v0.10.1) [一键更新]
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.9.9",
3
+ "version": "0.10.1",
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": {
@@ -6,7 +6,6 @@ window.__ModuleLoader__.load({
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react = require("react");
8
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
10
9
  //#region src/client/locales.ts
11
10
  /**
12
11
  * Switchblade management page dictionaries.
@@ -156,14 +155,26 @@ window.__ModuleLoader__.load({
156
155
  const GLASS_ATTR = "data-ar-glass";
157
156
  const CSS_TAG = "prompt-skill-armory/background";
158
157
  const BACKGROUND_CSS = `
159
- .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; }
160
162
  .ar-bg-layer .ar-bg-image { width: 100%; height: 100%; display: block; border: 0;
161
163
  object-fit: var(--ar-bg-fit, cover); opacity: var(--ar-bg-opacity, 1);
162
164
  filter: blur(var(--ar-bg-blur, 0px)); transform: scale(var(--ar-bg-scale, 1)); transform-origin: center; }
163
- .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;
164
166
  background: rgba(255,255,255, var(--ar-bg-scrim, 0.25)); }
165
167
  body[data-ds-dark-theme] .ar-bg-scrim { background: rgba(0,0,0, var(--ar-bg-scrim, 0.25)); }
166
- 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
+
167
178
  body[${GLASS_ATTR}] [data-composer-card],
168
179
  body[${GLASS_ATTR}] [class*="_bubble"]:not([role="tooltip"]),
169
180
  body[${GLASS_ATTR}] .md-code-block,
@@ -231,7 +242,11 @@ window.__ModuleLoader__.load({
231
242
  try {
232
243
  injectBackgroundCss();
233
244
  const hasSource = settings.url !== "" || settings.uploadId !== "";
234
- 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
+ ]) {
235
250
  this.rememberOnce(prop);
236
251
  document.body.style.setProperty(prop, "transparent");
237
252
  }
@@ -358,17 +373,17 @@ window.__ModuleLoader__.load({
358
373
  const notifyBg = () => {
359
374
  for (const l of bgListeners) l();
360
375
  };
361
- let bgApi;
362
- /** Bind the transport to a live connection API (set once at plugin apply). */
363
- function initBackgroundClient(api) {
364
- 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;
365
380
  }
366
381
  /** Surface key: separate wallpaper per web vs desktop (they share the settings doc). */
367
382
  const isDesktopSurface = typeof navigator !== "undefined" && navigator.userAgent.toLowerCase().includes("electron");
368
383
  const surfaceKey = () => isDesktopSurface ? "backgroundDesktop" : "backgroundWeb";
369
384
  /** Read the background section for the current surface from the switchblade settings. */
370
385
  function readSection(value) {
371
- const raw = (value.namespaces?.find((n) => n.ns === "switchblade")?.value)?.[surfaceKey()];
386
+ const raw = value?.[surfaceKey()];
372
387
  return {
373
388
  ...DEFAULT_BACKGROUND,
374
389
  ...typeof raw === "object" && raw !== null ? raw : {}
@@ -386,15 +401,15 @@ window.__ModuleLoader__.load({
386
401
  },
387
402
  /** Fetch the durable section. @returns true on success (status ready). */
388
403
  async load() {
389
- if (bgApi === void 0) {
404
+ if (bgScope === void 0) {
390
405
  bgState.status = "error";
391
406
  return false;
392
407
  }
393
408
  try {
394
- const res = await bgApi.settings.describe({});
395
- 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;
396
411
  bgState.status = "ready";
397
- bgState.value = readSection(res.result.value);
412
+ bgState.value = readSection(snap.value);
398
413
  notifyBg();
399
414
  return true;
400
415
  } catch {
@@ -403,17 +418,13 @@ window.__ModuleLoader__.load({
403
418
  }
404
419
  },
405
420
  async save(section) {
406
- if (bgApi === void 0) return;
421
+ if (bgScope === void 0) return;
407
422
  try {
408
- const res = await bgApi.settings.mutate({
409
- ns: "switchblade",
410
- ops: [{
411
- op: "set",
412
- path: [surfaceKey()],
413
- value: section
414
- }]
415
- });
416
- 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
+ }]);
417
428
  bgState.status = "ready";
418
429
  bgState.value = { ...section };
419
430
  } catch {
@@ -958,7 +969,7 @@ window.__ModuleLoader__.load({
958
969
  });
959
970
  }
960
971
  /** Bump with every release; keep in sync with package.json version + CHANGELOG. */
961
- const ARMORY_VERSION = "0.9.9";
972
+ const ARMORY_VERSION = "0.10.1";
962
973
  /** Compact duration: 45.2s / 2m42s / 1h05m. */
963
974
  function fmtDuration(ms) {
964
975
  const s = ms / 1e3;
@@ -3207,6 +3218,26 @@ window.__ModuleLoader__.load({
3207
3218
  }
3208
3219
  //#endregion
3209
3220
  //#region src/client/store.ts
3221
+ /** Local snapshot store engine (plain observable, sync flush). */
3222
+ function createSnapshotStore(init) {
3223
+ let current = init;
3224
+ const listeners = /* @__PURE__ */ new Set();
3225
+ return {
3226
+ getSnapshot: () => current,
3227
+ subscribe(listener) {
3228
+ listeners.add(listener);
3229
+ return () => {
3230
+ listeners.delete(listener);
3231
+ };
3232
+ },
3233
+ set(next) {
3234
+ current = next;
3235
+ for (const l of [...listeners]) try {
3236
+ l();
3237
+ } catch {}
3238
+ }
3239
+ };
3240
+ }
3210
3241
  /** Initial (idle) state. */
3211
3242
  const IDLE = {
3212
3243
  status: "idle",
@@ -3221,14 +3252,27 @@ window.__ModuleLoader__.load({
3221
3252
  return error instanceof Error ? error.message : String(error);
3222
3253
  }
3223
3254
  var SwitchbladeSectionController = class {
3224
- api;
3255
+ scope;
3256
+ remote;
3225
3257
  sessionId;
3226
3258
  /** Snapshot store backing the section's view state. */
3227
- store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)(IDLE);
3228
- constructor(api, sessionId) {
3229
- this.api = api;
3259
+ store = createSnapshotStore(IDLE);
3260
+ constructor(scope, remote, sessionId) {
3261
+ this.scope = scope;
3262
+ this.remote = remote;
3230
3263
  this.sessionId = sessionId;
3231
3264
  }
3265
+ /** 2.0.9 settings read: scope mirror snapshot (never the old api.settings). */
3266
+ describeSettings() {
3267
+ const snap = this.scope.getSnapshot();
3268
+ if (snap.status !== "ready" || snap.value === void 0) return void 0;
3269
+ return this.sectionFromSettings(snap.value, "switchblade");
3270
+ }
3271
+ /** 2.0.9 settings write: scope.mutate(ops) — Host fold + re-inject. */
3272
+ async mutateSettings(ops) {
3273
+ if (this.scope.getSnapshot().status !== "ready") throw new Error("settings scope not ready");
3274
+ await this.scope.mutate(ops);
3275
+ }
3232
3276
  /**
3233
3277
  * Load skills, prompts, and installed skills. Prompts and installed
3234
3278
  * skills come from the `switchblade` settings namespace (the Host watches
@@ -3241,16 +3285,14 @@ window.__ModuleLoader__.load({
3241
3285
  });
3242
3286
  try {
3243
3287
  const sessionId = this.sessionId?.();
3244
- const calls = [this.api.settings.describe({})];
3245
- if (sessionId !== void 0) calls.push(this.api.skills.list({ sessionId }));
3246
- const [settingsRes, skillRes] = await Promise.all(calls);
3247
- if (!settingsRes.result.ok) throw new Error(`settings.describe: ${settingsRes.result.error.message}`);
3248
- const skills = skillRes !== void 0 && skillRes.result.ok ? skillRes.result.value.skills.map((skill) => ({
3288
+ const calls = [Promise.resolve(this.describeSettings())];
3289
+ if (sessionId !== void 0) calls.push(this.remote.skills.list({ request: { sessionId } }));
3290
+ const [switchbladeSection, skillRes] = await Promise.all(calls);
3291
+ const skills = skillRes !== void 0 && skillRes.ok && skillRes.value !== void 0 ? skillRes.value.skills.map((skill) => ({
3249
3292
  name: skill.name,
3250
3293
  description: skill.description,
3251
3294
  modelInvocable: skill.modelInvocable
3252
3295
  })) : [];
3253
- const switchbladeSection = this.sectionFromSettings(settingsRes.result.value, "switchblade");
3254
3296
  const prompts = Array.isArray(switchbladeSection?.prompts) ? switchbladeSection.prompts : [];
3255
3297
  const installedSkills = Array.isArray(switchbladeSection?.installedSkills) ? switchbladeSection.installedSkills.map((s) => ({
3256
3298
  name: s.name ?? "",
@@ -3292,9 +3334,13 @@ window.__ModuleLoader__.load({
3292
3334
  });
3293
3335
  }
3294
3336
  }
3295
- /** Read one namespace's user section from a settings.describe value. */
3337
+ /** Read one namespace's section from a settings value. The 2.0.9 scope
3338
+ * snapshot carries the bound namespace's own value; older describe payloads
3339
+ * carry a `namespaces[]` table — accept both. */
3296
3340
  sectionFromSettings(value, ns) {
3297
3341
  if (typeof value !== "object" || value === null) return void 0;
3342
+ const asSection = value;
3343
+ if (Array.isArray(asSection.prompts) || Array.isArray(asSection.installedSkills) || asSection.mcpServers !== void 0) return asSection;
3298
3344
  const entries = value.namespaces;
3299
3345
  if (!Array.isArray(entries)) return void 0;
3300
3346
  for (const entry of entries) {
@@ -3307,24 +3353,20 @@ window.__ModuleLoader__.load({
3307
3353
  }
3308
3354
  /** Add a prompt. */
3309
3355
  async addPrompt(input) {
3310
- const res = await this.api.settings.mutate({
3311
- ns: "switchblade",
3312
- ops: [{
3313
- op: "set",
3314
- path: ["prompts"],
3315
- value: [...this.currentPrompts(), {
3316
- id: this.slugify(input.name),
3317
- name: input.name,
3318
- description: input.description,
3319
- content: input.content,
3320
- order: this.currentPrompts().length,
3321
- enabled: true,
3322
- isDefault: this.currentPrompts().length === 0,
3323
- ...input.scope === void 0 || input.scope.type === "global" ? {} : { scope: input.scope }
3324
- }]
3356
+ await this.mutateSettings([{
3357
+ op: "set",
3358
+ path: ["prompts"],
3359
+ value: [...this.currentPrompts(), {
3360
+ id: this.slugify(input.name),
3361
+ name: input.name,
3362
+ description: input.description,
3363
+ content: input.content,
3364
+ order: this.currentPrompts().length,
3365
+ enabled: true,
3366
+ isDefault: this.currentPrompts().length === 0,
3367
+ ...input.scope === void 0 || input.scope.type === "global" ? {} : { scope: input.scope }
3325
3368
  }]
3326
- });
3327
- if (!res.result.ok) throw new Error(res.result.error.message);
3369
+ }]);
3328
3370
  await this.load();
3329
3371
  }
3330
3372
  /** Toggle one prompt's enabled state. */
@@ -3361,15 +3403,11 @@ window.__ModuleLoader__.load({
3361
3403
  }
3362
3404
  /** Persist the prompt list through the settings RPC. */
3363
3405
  async writePrompts(prompts) {
3364
- const res = await this.api.settings.mutate({
3365
- ns: "switchblade",
3366
- ops: [{
3367
- op: "set",
3368
- path: ["prompts"],
3369
- value: prompts
3370
- }]
3371
- });
3372
- if (!res.result.ok) throw new Error(res.result.error.message);
3406
+ await this.mutateSettings([{
3407
+ op: "set",
3408
+ path: ["prompts"],
3409
+ value: prompts
3410
+ }]);
3373
3411
  await this.load();
3374
3412
  }
3375
3413
  /** Current prompt list from the loaded snapshot. */
@@ -3389,15 +3427,11 @@ window.__ModuleLoader__.load({
3389
3427
  content: input.content,
3390
3428
  enabled: true
3391
3429
  }];
3392
- const res = await this.api.settings.mutate({
3393
- ns: "switchblade",
3394
- ops: [{
3395
- op: "set",
3396
- path: ["installedSkills"],
3397
- value: next
3398
- }]
3399
- });
3400
- if (!res.result.ok) throw new Error(res.result.error.message);
3430
+ await this.mutateSettings([{
3431
+ op: "set",
3432
+ path: ["installedSkills"],
3433
+ value: next
3434
+ }]);
3401
3435
  await this.load();
3402
3436
  }
3403
3437
  /** Toggle one installed skill's enabled state. */
@@ -3406,29 +3440,21 @@ window.__ModuleLoader__.load({
3406
3440
  ...s,
3407
3441
  enabled
3408
3442
  } : s);
3409
- const res = await this.api.settings.mutate({
3410
- ns: "switchblade",
3411
- ops: [{
3412
- op: "set",
3413
- path: ["installedSkills"],
3414
- value: next
3415
- }]
3416
- });
3417
- if (!res.result.ok) throw new Error(res.result.error.message);
3443
+ await this.mutateSettings([{
3444
+ op: "set",
3445
+ path: ["installedSkills"],
3446
+ value: next
3447
+ }]);
3418
3448
  await this.load();
3419
3449
  }
3420
3450
  /** Uninstall one installed skill. */
3421
3451
  async uninstallSkill(name) {
3422
3452
  const next = this.currentInstalledSkills().filter((s) => s.name !== name);
3423
- const res = await this.api.settings.mutate({
3424
- ns: "switchblade",
3425
- ops: [{
3426
- op: "set",
3427
- path: ["installedSkills"],
3428
- value: next
3429
- }]
3430
- });
3431
- if (!res.result.ok) throw new Error(res.result.error.message);
3453
+ await this.mutateSettings([{
3454
+ op: "set",
3455
+ path: ["installedSkills"],
3456
+ value: next
3457
+ }]);
3432
3458
  await this.load();
3433
3459
  }
3434
3460
  /** Update an installed skill's name/description/content. */
@@ -3439,15 +3465,11 @@ window.__ModuleLoader__.load({
3439
3465
  description: patch.description ?? s.description,
3440
3466
  content: patch.content ?? s.content
3441
3467
  } : s);
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);
3468
+ await this.mutateSettings([{
3469
+ op: "set",
3470
+ path: ["installedSkills"],
3471
+ value: next
3472
+ }]);
3451
3473
  await this.load();
3452
3474
  }
3453
3475
  /** Current installed skills from the loaded snapshot. */
@@ -3459,18 +3481,14 @@ window.__ModuleLoader__.load({
3459
3481
  * watch sees pendingZip and installs it (skil-filesystem then discovers it).
3460
3482
  */
3461
3483
  async installSkillFromZip(name, dataBase64) {
3462
- const res = await this.api.settings.mutate({
3463
- ns: "switchblade",
3464
- ops: [{
3465
- op: "set",
3466
- path: ["pendingZip"],
3467
- value: {
3468
- name,
3469
- dataBase64
3470
- }
3471
- }]
3472
- });
3473
- if (!res.result.ok) throw new Error(res.result.error.message);
3484
+ await this.mutateSettings([{
3485
+ op: "set",
3486
+ path: ["pendingZip"],
3487
+ value: {
3488
+ name,
3489
+ dataBase64
3490
+ }
3491
+ }]);
3474
3492
  await new Promise((r) => setTimeout(r, 500));
3475
3493
  await this.load();
3476
3494
  }
@@ -3507,32 +3525,24 @@ window.__ModuleLoader__.load({
3507
3525
  * after a short delay so the panel shows the fresh tool list / error.
3508
3526
  */
3509
3527
  async testMcpServer(name) {
3510
- const res = await this.api.settings.mutate({
3511
- ns: "switchblade",
3512
- ops: [{
3513
- op: "set",
3514
- path: ["mcpTestRequest"],
3515
- value: {
3516
- serverName: name,
3517
- ts: Date.now()
3518
- }
3519
- }]
3520
- });
3521
- if (!res.result.ok) throw new Error(res.result.error.message);
3528
+ await this.mutateSettings([{
3529
+ op: "set",
3530
+ path: ["mcpTestRequest"],
3531
+ value: {
3532
+ serverName: name,
3533
+ ts: Date.now()
3534
+ }
3535
+ }]);
3522
3536
  await new Promise((r) => setTimeout(r, 2e3));
3523
3537
  await this.load();
3524
3538
  }
3525
3539
  /** Persist the MCP server config list. */
3526
3540
  async writeMcpServers(servers) {
3527
- const res = await this.api.settings.mutate({
3528
- ns: "switchblade",
3529
- ops: [{
3530
- op: "set",
3531
- path: ["mcpServers"],
3532
- value: servers
3533
- }]
3534
- });
3535
- if (!res.result.ok) throw new Error(res.result.error.message);
3541
+ await this.mutateSettings([{
3542
+ op: "set",
3543
+ path: ["mcpServers"],
3544
+ value: servers
3545
+ }]);
3536
3546
  await this.load();
3537
3547
  }
3538
3548
  /** Current MCP server list from the loaded snapshot. */
@@ -3542,11 +3552,18 @@ window.__ModuleLoader__.load({
3542
3552
  };
3543
3553
  //#endregion
3544
3554
  //#region src/client/index.ts
3555
+ /**
3556
+ * Switchblade management page, browser half: registers the `settings.section`
3557
+ * navigation entry and renders the edgelord panel from the connection RPC
3558
+ * state. Global scope (root) — one management seat for every session.
3559
+ * @module @deepseek-ai/dsh-client-ui-switchblade
3560
+ */
3545
3561
  /** Required services (cordis fiber inject). */
3546
3562
  const inject = [
3547
3563
  "slots",
3548
3564
  "locale",
3549
- "connection",
3565
+ "settingsScope",
3566
+ "remote",
3550
3567
  "sessions"
3551
3568
  ];
3552
3569
  /**
@@ -3558,11 +3575,12 @@ window.__ModuleLoader__.load({
3558
3575
  zh,
3559
3576
  en
3560
3577
  }), "ui-switchblade: dictionaries");
3561
- const api = ctx.get("connection").api;
3578
+ const scope = ctx.get("settingsScope").bind({ namespace: "switchblade" });
3579
+ const remote = ctx.get("remote");
3562
3580
  const sessions = ctx.get("sessions");
3563
3581
  applyHintStyle();
3564
3582
  try {
3565
- initBackgroundClient(api);
3583
+ initBackgroundClient(scope);
3566
3584
  const paintBackground = () => {
3567
3585
  const s = backgroundClient.getSnapshot();
3568
3586
  if (s.status === "ready") applyBackground(s.value);
@@ -3577,7 +3595,7 @@ window.__ModuleLoader__.load({
3577
3595
  } catch (error) {
3578
3596
  console.warn("[switchblade] background init skipped:", error);
3579
3597
  }
3580
- const controller = new SwitchbladeSectionController(api, () => {
3598
+ const controller = new SwitchbladeSectionController(scope, remote, () => {
3581
3599
  const state = sessions.list.getSnapshot();
3582
3600
  return state.current === void 0 ? void 0 : state.current;
3583
3601
  });